From 58446ffaed2ad0e385fd9423420ca08344fb6017 Mon Sep 17 00:00:00 2001 From: William Muir Date: Mon, 14 Aug 2017 16:11:32 +1200 Subject: [PATCH] MarkRounding Message now sent out correctly. Added submark seqID attribute to each mark of a compound mark from parsing xml Added Rounding side attribute to each individual mark as read from the xml RoundingSide enum now has a method to get Enum from String literal Now store the closest mark to each yacht in each update for purpose of knowing which mark they round Minor code tidying, Added logger to serverToClientThread, removed 'serverLog' method removed obsolete code --- .../seng302/gameServer/MainServerThread.java | 2 +- .../gameServer/ServerToClientThread.java | 60 +-------- .../server/messages/MarkRoundingMessage.java | 5 +- .../server/messages/RoundingSide.java | 40 +++++- .../gameServer/server/simulator/Boat.java | 125 ------------------ .../gameServer/server/simulator/Corner.java | 91 ------------- .../server/simulator/RoundingType.java | 43 ------ .../server/simulator/parsers/BoatsParser.java | 19 --- .../simulator/parsers/CourseParser.java | 118 ----------------- .../server/simulator/parsers/FileParser.java | 51 ------- .../server/simulator/parsers/RaceParser.java | 65 --------- src/main/java/seng302/model/Yacht.java | 81 +++++++----- .../java/seng302/model/mark/CompoundMark.java | 23 +++- src/main/java/seng302/model/mark/Mark.java | 17 ++- .../java/seng302/model/mark/MarkOrder.java | 2 + .../java/seng302/utilities/XMLParser.java | 3 +- .../java/seng302/visualiser/GameView.java | 10 ++ .../seng302/model/mark/CompoundMarkTest.java | 4 +- 18 files changed, 144 insertions(+), 615 deletions(-) delete mode 100644 src/main/java/seng302/gameServer/server/simulator/Boat.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/Corner.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/RoundingType.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/parsers/BoatsParser.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/parsers/CourseParser.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/parsers/FileParser.java delete mode 100644 src/main/java/seng302/gameServer/server/simulator/parsers/RaceParser.java diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 6e827d95..dca712f3 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -82,7 +82,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn public void updateClients() { for (ServerToClientThread serverToClientThread : serverToClientThreads) { - serverToClientThread.updateClient(); + serverToClientThread.sendBoatLocationPackets(); } } diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index c77607e3..223598bd 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -18,6 +18,8 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.zip.CRC32; import java.util.zip.Checksum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import seng302.gameServer.server.messages.BoatActionType; import seng302.gameServer.server.messages.BoatLocationMessage; import seng302.gameServer.server.messages.BoatStatus; @@ -46,8 +48,7 @@ import seng302.utilities.XMLGenerator; */ public class ServerToClientThread implements Runnable, Observer { - private static final Integer LOG_LEVEL = 1; - private static final Integer MAX_ID_ATTEMPTS = 10; + private Logger logger = LoggerFactory.getLogger(ServerToClientThread.class); private Thread thread; @@ -57,11 +58,6 @@ public class ServerToClientThread implements Runnable, Observer { private ByteArrayOutputStream crcBuffer; - private Boolean userIdentified = false; - private Boolean connected = true; - private Boolean updateClient = true; -// private Boolean initialisedRace = true; - private Integer seqNo; private Integer sourceId; @@ -120,13 +116,6 @@ public class ServerToClientThread implements Runnable, Observer { GameState.addPlayer(new Player(socket, yacht)); } - static void serverLog(String message, int logLevel) { - if (logLevel <= LOG_LEVEL) { - System.out.println( - "[SERVER " + LocalDateTime.now().toLocalTime().toString() + "] " + message); - } - } - @Override public void update(Observable o, Object arg) { if (arg != null) { @@ -172,20 +161,6 @@ public class ServerToClientThread implements Runnable, Observer { while (socket.isConnected()) { 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 -// ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Hello, it's me"); -// sendMessage(chatterMessage); -// try { -// GameState.outputState(os); -// } catch (IOException e) { -// System.out.println("IO error in server thread upon writing to output stream"); -// } -// sendBoatLocationPackets(); - updateClient = false; - } - crcBuffer = new ByteArrayOutputStream(); sync1 = readByte(); sync2 = readByte(); @@ -219,7 +194,7 @@ public class ServerToClientThread implements Runnable, Observer { break; } } else { - serverLog("Packet has been dropped", 1); + logger.warn("Packet has been dropped", 1); } } } catch (Exception e) { @@ -257,27 +232,6 @@ public class ServerToClientThread implements Runnable, Observer { sendMessage(xmlMessage); } - public void updateClient() { - sendBoatLocationPackets(); - updateClient = true; - } - - - /** - * Tries to confirm the connection just accepted. - * Sends ID, expects that ID echoed for confirmation, - * 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 Boolean threeWayHandshake(Integer id) { - - return true; - } - private void closeSocket() { try { socket.close(); @@ -295,7 +249,7 @@ public class ServerToClientThread implements Runnable, Observer { crcBuffer.write(currentByte); } catch (IOException e) { e.printStackTrace(); - serverLog("Socket read failed", 1); + logger.warn("Socket read failed", 1); } if (currentByte == -1) { throw new Exception(); @@ -324,7 +278,7 @@ public class ServerToClientThread implements Runnable, Observer { //serverLog("Player " + sourceId + " side socket disconnected", 1); return; } catch (IOException e) { - serverLog("Message send failed", 1); + logger.warn("Message send failed", 1); } } @@ -334,7 +288,7 @@ public class ServerToClientThread implements Runnable, Observer { } - private void sendBoatLocationPackets() { + public void sendBoatLocationPackets() { ArrayList yachts = new ArrayList<>(GameState.getYachts().values()); for (Yacht yacht : yachts) { // System.out.println("[SERVER] Lat: " + yacht.getLocation().getLat() + " Lon: " + yacht.getLocation().getLng()); diff --git a/src/main/java/seng302/gameServer/server/messages/MarkRoundingMessage.java b/src/main/java/seng302/gameServer/server/messages/MarkRoundingMessage.java index b683930e..c2223f5d 100644 --- a/src/main/java/seng302/gameServer/server/messages/MarkRoundingMessage.java +++ b/src/main/java/seng302/gameServer/server/messages/MarkRoundingMessage.java @@ -1,5 +1,7 @@ package seng302.gameServer.server.messages; +import seng302.gameServer.GameState; + public class MarkRoundingMessage extends Message{ private final long MESSAGE_VERSION_NUMBER = 1; private final int MESSAGE_SIZE = 21; @@ -24,7 +26,7 @@ public class MarkRoundingMessage extends Message{ * @param markId markId */ public MarkRoundingMessage(int ackNumber, int raceId, int sourceId, RoundingBoatStatus roundingBoatStatus, - RoundingSide roundingSide, int markId){ + RoundingSide roundingSide, MarkType markType, int markId) { this.time = System.currentTimeMillis() / 1000L; this.ackNumber = ackNumber; this.raceId = raceId; @@ -44,6 +46,7 @@ public class MarkRoundingMessage extends Message{ putInt((int) sourceId, 4); putByte((byte) boatStatus.getCode()); putByte((byte) roundingSide.getCode()); + putByte((byte) markType.getCode()); putByte((byte) markId); writeCRC(); diff --git a/src/main/java/seng302/gameServer/server/messages/RoundingSide.java b/src/main/java/seng302/gameServer/server/messages/RoundingSide.java index 6bb4c553..efb4c929 100644 --- a/src/main/java/seng302/gameServer/server/messages/RoundingSide.java +++ b/src/main/java/seng302/gameServer/server/messages/RoundingSide.java @@ -4,17 +4,49 @@ package seng302.gameServer.server.messages; * The side the boat rounded the mark */ public enum RoundingSide { - UNKNOWN(0), - PORT(1), - STARBOARD(2); + UNKNOWN(0, "Unknown"), + PORT(1, "Port"), + STARBOARD(2, "Stbd"), + SP(3, "SP"), + PS(4, "PS"); + private long code; + private String name; - RoundingSide(long code) { + RoundingSide(long code, String name) { this.code = code; + this.name = name; } public long getCode(){ return code; } + + public String getName() { + return name; + } + + public static RoundingSide getRoundingSide(String identifier) { + RoundingSide roundingSide = UNKNOWN; + switch (identifier) { + case "Unknown": + roundingSide = UNKNOWN; + break; + case "Port": + roundingSide = PORT; + break; + case "Stbd": + roundingSide = STARBOARD; + break; + case "SP": + roundingSide = SP; + break; + case "PS": + roundingSide = PS; + break; + } + + return roundingSide; + } } diff --git a/src/main/java/seng302/gameServer/server/simulator/Boat.java b/src/main/java/seng302/gameServer/server/simulator/Boat.java deleted file mode 100644 index c083dbf2..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/Boat.java +++ /dev/null @@ -1,125 +0,0 @@ -package seng302.gameServer.server.simulator; - -import seng302.model.GeoPoint; -import seng302.utilities.GeoUtility; - -public class Boat { - - private int sourceID; - private double lat; - private double lng; - private double speed; // in mm/sec - private String boatName, shortName, shorterName; - private boolean isFinished; - private long estimatedTimeTillFinish; - - private Corner lastPassedCorner, headingCorner; - - public Boat(int sourceID, String boatName) { - this.sourceID = sourceID; - this.boatName = boatName; - this.isFinished = false; - estimatedTimeTillFinish = 0; - } - - /** - * Moves boat to the heading direction for a given time duration - * @param heading moving direction in degree. - * @param duration moving duration in millisecond. - */ - public void move(double heading, double duration) { - Double distance = speed * duration / 1000000; // convert mm to meter - GeoPoint originPos = new GeoPoint(lat, lng); - GeoPoint newPos = GeoUtility.getGeoCoordinate(originPos, heading, distance); - this.lat = newPos.getLat(); - this.lng = newPos.getLng(); - } - - public String toString() { - return String.format("Boat (%d): lat: %f, lng: %f", sourceID, lat, lng); - } - - public int getSourceID() { - return sourceID; - } - - public void setSourceID(int sourceID) { - this.sourceID = sourceID; - } - - public double getLat() { - return lat; - } - - public void setLat(double lat) { - this.lat = lat; - } - - public double getLng() { - return lng; - } - - public void setLng(double lng) { - this.lng = lng; - } - - public double getSpeed() { - return speed; - } - - public void setSpeed(double speed) { - this.speed = speed; - } - - public String getBoatName() { - return boatName; - } - - public void setBoatName(String boatName) { - this.boatName = boatName; - } - - public String getShortName() { - return shortName; - } - - public void setShortName(String shortName) { - this.shortName = shortName; - } - - public String getShorterName() { - return shorterName; - } - - public void setShorterName(String shorterName) { - this.shorterName = shorterName; - } - - public Corner getLastPassedCorner() { - return lastPassedCorner; - } - - public void setLastPassedCorner(Corner lastPassedCorner) { - this.lastPassedCorner = lastPassedCorner; - } - - public Corner getHeadingCorner() { - return headingCorner; - } - - public void setHeadingCorner(Corner headingCorner) { - this.headingCorner = headingCorner; - } - - public boolean isFinished() { - return isFinished; - } - - public void setFinished(boolean finished) { - isFinished = finished; - } - - public long getEstimatedTimeTillFinish(){ - return (long) (-getSpeed()) + System.currentTimeMillis(); - } -} diff --git a/src/main/java/seng302/gameServer/server/simulator/Corner.java b/src/main/java/seng302/gameServer/server/simulator/Corner.java deleted file mode 100644 index 11c26104..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/Corner.java +++ /dev/null @@ -1,91 +0,0 @@ -package seng302.gameServer.server.simulator; - -import seng302.model.mark.CompoundMark; - -public class Corner { - - private int seqID; - private CompoundMark compoundMark; - //private int CompoundMarkID; - private RoundingType roundingType; - private int zoneSize; // size of the zone around a mark in boat-lengths. - - // TODO: this shouldn't be used in the future!!!! - private double bearingToNextCorner, distanceToNextCorner; - private Corner nextCorner; - - public Corner(int seqID, CompoundMark compoundMark, RoundingType roundingType, int zoneSize) { - this.seqID = seqID; - this.compoundMark = compoundMark; - this.roundingType = roundingType; - this.zoneSize = zoneSize; - } - - /** - * Prints out corner's info and its compound mark, good for testing - * @return a string showing its details - */ - @Override - public String toString() { - return String.format("Corner: %d - %s - %d, %s\n", - seqID, roundingType.getType(), zoneSize, compoundMark.toString()); - } - - public int getSeqID() { - return seqID; - } - - public void setSeqID(int seqID) { - this.seqID = seqID; - } - - public CompoundMark getCompoundMark() { - return compoundMark; - } - - public void setCompoundMark(CompoundMark compoundMark) { - this.compoundMark = compoundMark; - } - - public RoundingType getRoundingType() { - return roundingType; - } - - public void setRoundingType(RoundingType roundingType) { - this.roundingType = roundingType; - } - - public int getZoneSize() { - return zoneSize; - } - - public void setZoneSize(int zoneSize) { - this.zoneSize = zoneSize; - } - - - // TODO: next six setters & getters shouldn't be used in the future. - public double getBearingToNextCorner() { - return bearingToNextCorner; - } - - public void setBearingToNextCorner(double bearingToNextCorner) { - this.bearingToNextCorner = bearingToNextCorner; - } - - public double getDistanceToNextCorner() { - return distanceToNextCorner; - } - - public void setDistanceToNextCorner(double distanceToNextCorner) { - this.distanceToNextCorner = distanceToNextCorner; - } - - public Corner getNextCorner() { - return nextCorner; - } - - public void setNextCorner(Corner nextCorner) { - this.nextCorner = nextCorner; - } -} diff --git a/src/main/java/seng302/gameServer/server/simulator/RoundingType.java b/src/main/java/seng302/gameServer/server/simulator/RoundingType.java deleted file mode 100644 index aa1bca8e..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/RoundingType.java +++ /dev/null @@ -1,43 +0,0 @@ -package seng302.gameServer.server.simulator; - -public enum RoundingType { - - // the mark should be rounded to port (boat's left) - PORT("Port"), - - // the mark should be rounded to starboard (boat's right) - STARBOARD("Stbd"), - - // the boat within the compound mark with the SeqID of 1 should be rounded - // to starboard and the boat within the compound mark with the SeqID of 2 - // should be rounded to port. - SP("SP"), - - // the opposite of SP - PS("PS"); - - private String type; - - RoundingType(String type) { - this.type = type; - } - - public String getType() { - return this.type; - } - - public static RoundingType typeOf(String type) { - switch (type) { - case "Port": - return PORT; - case "Stbd": - return STARBOARD; - case "SP": - return SP; - case "PS": - return PS; - default: - return null; - } - } -} diff --git a/src/main/java/seng302/gameServer/server/simulator/parsers/BoatsParser.java b/src/main/java/seng302/gameServer/server/simulator/parsers/BoatsParser.java deleted file mode 100644 index 17a46eae..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/parsers/BoatsParser.java +++ /dev/null @@ -1,19 +0,0 @@ -package seng302.gameServer.server.simulator.parsers; - -import org.w3c.dom.Document; - - -/** - * Parses the race xml file to get course details - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public class BoatsParser extends FileParser { - - private Document doc; - - public BoatsParser(String path) { - super(path); - this.doc = this.parseFile(); - } - -} diff --git a/src/main/java/seng302/gameServer/server/simulator/parsers/CourseParser.java b/src/main/java/seng302/gameServer/server/simulator/parsers/CourseParser.java deleted file mode 100644 index 36164af2..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/parsers/CourseParser.java +++ /dev/null @@ -1,118 +0,0 @@ -package seng302.gameServer.server.simulator.parsers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import seng302.gameServer.server.simulator.Corner; -import seng302.gameServer.server.simulator.RoundingType; -import seng302.model.mark.CompoundMark; -import seng302.model.mark.Mark; - -/** - * Parses the race xml file to get course details - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public class CourseParser extends FileParser { - - private Document doc; - private Map compoundMarksMap; - - public CourseParser(String path) { - super(path); - this.doc = this.parseFile(); - } - - // TODO: should handle error / invalid file gracefully - protected List getCourse() { - compoundMarksMap = getCompoundMarks(doc.getDocumentElement()); - List corners = new ArrayList<>(); - NodeList cMarksSequence = doc.getElementsByTagName("Corner"); - - for (int i = 0; i < cMarksSequence.getLength(); i++) { - corners.add(getCorner(cMarksSequence.item(i))); - } - return corners; - } - - - private Corner getCorner(Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) node; - - Integer seqId = Integer.valueOf(e.getAttribute("SeqID")); - Integer cMarkId = Integer.valueOf(e.getAttribute("CompoundMarkID")); - CompoundMark cMark = compoundMarksMap.get(cMarkId); - RoundingType roundingType = RoundingType.typeOf(e.getAttribute("Rounding")); - Integer zoneSize = Integer.valueOf(e.getAttribute("ZoneSize")); - - return new Corner(seqId, cMark, roundingType, zoneSize); - } - return null; - } - - private Map getCompoundMarks(Node node) { - Map compoundMarksMap = new HashMap<>(); - - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - NodeList cMarks = element.getElementsByTagName("CompoundMark"); - - // loop through all compound marks who are the children of course node - for (int i = 0; i < cMarks.getLength(); i++) { - CompoundMark cMark = getCompoundMark(cMarks.item(i)); - if (cMark != null) - compoundMarksMap.put(cMark.getId(), cMark); - } - - return compoundMarksMap; - } - return null; - } - - - private CompoundMark getCompoundMark(Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) node; - Integer markID = Integer.valueOf(e.getAttribute("CompoundMarkID")); - String name = e.getAttribute("Name"); - - NodeList marks = e.getElementsByTagName("Mark"); - List subMarks = new ArrayList<>(); - for (int i = 0; i < marks.getLength(); i++) { - Mark mark = getMark(marks.item(i)); - if (mark != null) { - subMarks.add(mark); - } - } - - return new CompoundMark(markID, name, subMarks); - } - System.out.println("Failed to create compound mark."); - return null; - } - - - private Mark getMark(Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) node; - Integer seqId = Integer.valueOf(e.getAttribute("SeqID")); - String name = e.getAttribute("Name"); - Double lat = Double.valueOf(e.getAttribute("TargetLat")); - Double lng = Double.valueOf(e.getAttribute("TargetLng")); - Integer sourceId = Integer.valueOf(e.getAttribute("SourceID")); - - Mark mark = new Mark(name, lat, lng, sourceId); - mark.setSeqID(seqId); - - return mark; - } - System.out.println("Failed to create mark."); - return null; - } - -} diff --git a/src/main/java/seng302/gameServer/server/simulator/parsers/FileParser.java b/src/main/java/seng302/gameServer/server/simulator/parsers/FileParser.java deleted file mode 100644 index 87021893..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/parsers/FileParser.java +++ /dev/null @@ -1,51 +0,0 @@ -package seng302.gameServer.server.simulator.parsers; - -import java.io.InputStream; -import java.io.StringReader; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -/** - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public abstract class FileParser { - - private String filePath; - - public FileParser() {} - - public FileParser(String path) { - this.filePath = path; - } - - protected Document parseFile() { - try { - InputStream is = getClass().getResourceAsStream(this.filePath); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(is); - // optional, in order to recover info from broken line. - doc.getDocumentElement().normalize(); - return doc; - } catch (Exception e) { - System.out.println("[FileParser] Exception"); - return null; - } - } - - protected Document parseFile(String xmlString) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(new InputSource(new StringReader(xmlString))); - // optional, in order to recover info from broken line. - doc.getDocumentElement().normalize(); - return doc; - } catch (Exception e) { - System.out.println("[FileParser] Exception"); - } - return null; - } -} diff --git a/src/main/java/seng302/gameServer/server/simulator/parsers/RaceParser.java b/src/main/java/seng302/gameServer/server/simulator/parsers/RaceParser.java deleted file mode 100644 index 960ff8fc..00000000 --- a/src/main/java/seng302/gameServer/server/simulator/parsers/RaceParser.java +++ /dev/null @@ -1,65 +0,0 @@ -package seng302.gameServer.server.simulator.parsers; - -import java.util.ArrayList; -import java.util.List; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import seng302.gameServer.server.simulator.Boat; -import seng302.gameServer.server.simulator.Corner; - -/** - * Parses the race xml file to get course details - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public class RaceParser extends FileParser { - - private Document doc; - private String path; - - public RaceParser(String path) { - super(path); - this.path = path; - this.doc = this.parseFile(); - } - - /** - * Parses race.xml file and returns a list of corner which is the race course. - * @return a list of ordered corner to represent the course. - */ - public List getCourse() { - CourseParser cp = new CourseParser(path); - return cp.getCourse(); - } - - /** - * Parses race.xml file and return a list of boats which will compete in the - * race. - * @return a list of boats that are going to compete in the race. - */ - public List getBoats() { - NodeList yachts = doc.getDocumentElement().getElementsByTagName("Yacht"); - List boats = new ArrayList<>(); - - for (int i = 0; i < yachts.getLength(); i++) { - boats.add(getBoat(yachts.item(i))); - } - return boats; - } - - /** - * Parses a single boat from the given node - * @param node a node within a boat tag - * @return a boat instance parsed from the given node - */ - private Boat getBoat(Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) node; - - Integer sourceId = Integer.valueOf(e.getAttribute("SourceID")); - return new Boat(sourceId, "Test Boat"); - } - return null; - } -} diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index d395df2b..da1b434f 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -16,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import seng302.gameServer.GameState; import seng302.gameServer.server.messages.MarkRoundingMessage; +import seng302.gameServer.server.messages.MarkType; import seng302.gameServer.server.messages.Message; import seng302.gameServer.server.messages.RoundingBoatStatus; import seng302.gameServer.server.messages.RoundingSide; @@ -70,6 +71,7 @@ public class Yacht extends Observable { //MARK ROUNDING INFO private GeoPoint lastLocation; //For purposes of mark rounding calculations private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round + private Mark closestCurrentMark; private Boolean hasPassedLine; private Boolean hasPassedThroughGate; private Boolean finishedRace; @@ -113,7 +115,7 @@ public class Yacht extends Observable { Double windSpeedKnots = GameState.getWindSpeedKnots(); Double trueWindAngle = Math.abs(GameState.getWindDirection() - heading); Double boatSpeedInKnots = PolarTable.getBoatSpeed(windSpeedKnots, trueWindAngle); - Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000; + Double maxBoatSpeed = boatSpeedInKnots / 1.943844492 * 1000 * 2; if (sailIn && velocity <= maxBoatSpeed && maxBoatSpeed != 0d) { if (velocity < maxBoatSpeed) { @@ -160,14 +162,39 @@ public class Yacht extends Observable { super.addObserver(o); } - private void sendMarkRoundingMessage(Integer passedMarkSeqID) { + private void sendMarkRoundingMessage() { + CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID); + MarkType markType = (currentMark.isGate()) ? MarkType.GATE : MarkType.ROUNDING_MARK; + // TODO: 13/8/17 figure out the rounding side, rounded mark source ID and boat status. Message markRoundingMessage = new MarkRoundingMessage(0, 0, - getSourceId(), RoundingBoatStatus.RACING, RoundingSide.UNKNOWN, - GameState.getMarkOrder().getCurrentMark(passedMarkSeqID).getSubMark(1).getSourceID()); - logger.debug("Sending mark rounding message..."); + sourceId, RoundingBoatStatus.RACING, closestCurrentMark.getRoundingSide(), markType, + closestCurrentMark.getSourceID()); setChanged(); notifyObservers(markRoundingMessage); + logMarkRounding(currentMark); + + hasPassedLine = false; + hasEnteredRoundingZone = false; + hasPassedThroughGate = false; + currentMarkSeqID++; + } + + private void logMarkRounding(CompoundMark currentMark) { + logger.debug( + String.format("Sending Mark Rounding Message:\n" + + "AckNumber %d\n" + + "RaceID %d\n" + + "BoatSourceID %d\n" + + "BoatStatus %s\n" + + "Rounding Side %s\n" + + "MarkSeqID %d", + 0, + 0, + sourceId, + RoundingBoatStatus.RACING.name(), + closestCurrentMark.getRoundingSide().getName(), + currentMark.getSubMark(1).getSourceID())); } /** @@ -186,8 +213,15 @@ public class Yacht extends Observable { Mark sub2 = nextMark.getSubMark(2); Double distance1 = GeoUtility.getDistance(location, sub1); Double distance2 = GeoUtility.getDistance(location, sub2); - return (distance1 < distance2) ? distance1 : distance2; + if (distance1 < distance2) { + closestCurrentMark = sub1; + return distance1; + } else { + closestCurrentMark = sub2; + return distance2; + } } else { + closestCurrentMark = nextMark.getSubMark(1); return GeoUtility.getDistance(location, nextMark.getSubMark(1)); } } @@ -224,9 +258,8 @@ public class Yacht extends Observable { if (crossedLine > 0) { Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, nextMark.getMidPoint()); if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) { - sendMarkRoundingMessage(currentMarkSeqID); - currentMarkSeqID++; - logMarkRounding(currentMark); + closestCurrentMark = mark1; + sendMarkRoundingMessage(); } } } @@ -257,11 +290,7 @@ public class Yacht extends Observable { } if (hasPassedLine && hasEnteredRoundingZone) { - currentMarkSeqID++; - hasPassedLine = false; - hasEnteredRoundingZone = false; - hasPassedThroughGate = false; - logMarkRounding(currentMark); + sendMarkRoundingMessage(); } } @@ -297,9 +326,7 @@ public class Yacht extends Observable { if (prevMarkSide == nextMarkSide) { checkMarkRounding(currentMark); } else { - sendMarkRoundingMessage(currentMarkSeqID); - currentMarkSeqID++; - logMarkRounding(currentMark); + sendMarkRoundingMessage(); } } } @@ -318,12 +345,10 @@ public class Yacht extends Observable { if (crossedLine > 0) { Boolean isClockwiseCross = GeoUtility.isClockwise(mark1, mark2, prevMark.getMidPoint()); if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) { - sendMarkRoundingMessage(currentMarkSeqID); - currentMarkSeqID++; + closestCurrentMark = mark1; + sendMarkRoundingMessage(); finishedRace = true; - logMarkRounding(currentMark); logger.debug(sourceId + " finished"); - // TODO: 8/08/17 wmu16 - Do something! } } } @@ -683,20 +708,6 @@ public class Yacht extends Observable { } } - private void logMarkRounding(CompoundMark currentMark) { - String typeString = "mark"; - if (currentMark.isGate()) { - typeString = "gate"; - } - logger.debug( - String.format("BoatID %d passed %s %s with id %d. Now on leg %d", - sourceId, - typeString, - currentMark.getMarks().get(0).getName(), - currentMark.getId(), - currentMarkSeqID)); - } - public void addLocationListener(YachtLocationListener listener) { locationListeners.add(listener); } diff --git a/src/main/java/seng302/model/mark/CompoundMark.java b/src/main/java/seng302/model/mark/CompoundMark.java index fe5147de..70cd114f 100644 --- a/src/main/java/seng302/model/mark/CompoundMark.java +++ b/src/main/java/seng302/model/mark/CompoundMark.java @@ -2,6 +2,7 @@ package seng302.model.mark; import java.util.ArrayList; import java.util.List; +import seng302.gameServer.server.messages.RoundingSide; import seng302.model.GeoPoint; import seng302.utilities.GeoUtility; @@ -9,7 +10,6 @@ public class CompoundMark { private int compoundMarkId; private String name; - private List marks = new ArrayList<>(); private GeoPoint midPoint; @@ -55,6 +55,27 @@ public class CompoundMark { this.name = name; } + public void setRoundingSide(RoundingSide roundingSide) { + switch (roundingSide) { + case SP: + getSubMark(1).setRoundingSide(RoundingSide.STARBOARD); + getSubMark(2).setRoundingSide(RoundingSide.PORT); + break; + case PS: + getSubMark(1).setRoundingSide(RoundingSide.PORT); + getSubMark(2).setRoundingSide(RoundingSide.STARBOARD); + break; + case PORT: + getSubMark(1).setRoundingSide(RoundingSide.PORT); + break; + case STARBOARD: + getSubMark(1).setRoundingSide(RoundingSide.STARBOARD); + break; + + + } + } + /** * Returns the mark contained in the compound mark. Marks are numbered 1 to n; * @param singleMarkId the id of the desired mark contained in this compound mark. diff --git a/src/main/java/seng302/model/mark/Mark.java b/src/main/java/seng302/model/mark/Mark.java index 57d04974..de66166c 100644 --- a/src/main/java/seng302/model/mark/Mark.java +++ b/src/main/java/seng302/model/mark/Mark.java @@ -2,6 +2,7 @@ package seng302.model.mark; import java.util.ArrayList; import java.util.List; +import seng302.gameServer.server.messages.RoundingSide; import seng302.model.GeoPoint; /** @@ -19,11 +20,13 @@ public class Mark extends GeoPoint { private String name; private int sourceID; private List positionListeners = new ArrayList<>(); + private RoundingSide roundingSide; - public Mark(String name, double lat, double lng, int sourceID) { + public Mark(String name, int seqID, double lat, double lng, int sourceID) { super(lat, lng); this.name = name; this.sourceID = sourceID; + this.seqID = seqID; } /** @@ -39,10 +42,6 @@ public class Mark extends GeoPoint { return seqID; } - public void setSeqID(int seqID) { - this.seqID = seqID; - } - public String getName() { return name; } @@ -55,6 +54,14 @@ public class Mark extends GeoPoint { return sourceID; } + public RoundingSide getRoundingSide() { + return roundingSide; + } + + public void setRoundingSide(RoundingSide roundingSide) { + this.roundingSide = roundingSide; + } + public void setSourceID(int sourceID) { this.sourceID = sourceID; } diff --git a/src/main/java/seng302/model/mark/MarkOrder.java b/src/main/java/seng302/model/mark/MarkOrder.java index 1b744fc2..800e4e76 100644 --- a/src/main/java/seng302/model/mark/MarkOrder.java +++ b/src/main/java/seng302/model/mark/MarkOrder.java @@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import seng302.gameServer.server.messages.RoundingSide; import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.utilities.XMLGenerator; @@ -104,6 +105,7 @@ public class MarkOrder { for (Corner corner : corners){ CompoundMark compoundMark = marks.get(corner.getCompoundMarkID()); + compoundMark.setRoundingSide(RoundingSide.getRoundingSide(corner.getRounding())); course.add(compoundMark); } diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index c4c4348b..a88af9b4 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -277,11 +277,12 @@ public class XMLParser { for (int i = 0; i < childMarks.getLength(); i++) { Node markNode = childMarks.item(i); if (markNode.getNodeName().equals("Mark")) { + Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID"); Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID"); String markName = XMLParser.getNodeAttributeString(markNode, "Name"); Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat"); Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng"); - Mark mark = new Mark(markName, targetLat, targetLng, sourceID); + Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID); subMarks.add(mark); } } diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java index 73d49b89..14c8a319 100644 --- a/src/main/java/seng302/visualiser/GameView.java +++ b/src/main/java/seng302/visualiser/GameView.java @@ -201,6 +201,16 @@ public class GameView extends Pane { for (Mark mark : cMark.getMarks()) { makeAndBindMarker(mark, colour); } + + //UNCOMMENT THIS TO HIGHLIGHT SUBMARKS 1 and 2 RED AND GREEN RESPECTIVELY FOR DEBUG + //(instead of above for loop) +// for (Mark mark : cMark.getMarks()) { +// if (mark.getSeqID() == 1) { +// makeAndBindMarker(mark, Color.RED); +// } else { +// makeAndBindMarker(mark, Color.GREEN); +// } +// } //Create gate line if (cMark.isGate()) { for (int i = 1; i < cMark.getMarks().size(); i++) { diff --git a/src/test/java/seng302/model/mark/CompoundMarkTest.java b/src/test/java/seng302/model/mark/CompoundMarkTest.java index 83b2b2bb..90d5c099 100644 --- a/src/test/java/seng302/model/mark/CompoundMarkTest.java +++ b/src/test/java/seng302/model/mark/CompoundMarkTest.java @@ -26,8 +26,8 @@ public class CompoundMarkTest { @Before public void setUp() throws Exception { - mark1 = new Mark("Mark1", 57.670333, 11.842833, 0); - mark2 = new Mark("Mark2", 57.671524, 11.844495, 1); + mark1 = new Mark("Mark1", 1, 57.670333, 11.842833, 0); + mark2 = new Mark("Mark2", 2, 57.671524, 11.844495, 1); List gateMarks = new ArrayList(); gateMarks.add(mark1);