From df7264cc1faf0e1fdc0048d38c60ab2b0ccf2be7 Mon Sep 17 00:00:00 2001 From: Calum Date: Tue, 26 Sep 2017 23:34:19 +1300 Subject: [PATCH 1/4] Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts. #implement. --- .../seng302/gameServer/MainServerThread.java | 129 ++++++++++++++---- .../seng302/gameServer/MessageFactory.java | 3 +- .../gameServer/ServerToClientThread.java | 7 +- .../stream/xml/generator/RaceXMLTemplate.java | 14 +- .../java/seng302/utilities/XMLParser.java | 53 ++++++- .../visualiser/ClientToServerThread.java | 20 ++- .../java/seng302/visualiser/GameClient.java | 8 +- .../java/seng302/visualiser/MapMaker.java | 42 ++++-- .../dialogs/ServerCreationController.java | 24 ++-- src/main/resources/maps/default.xml | 2 + src/main/resources/maps/horseshoe.xml | 2 + .../server_config/xml_templates/race.ftlh | 4 +- .../java/seng302/models/MarkOrderTest.java | 37 +++-- 13 files changed, 259 insertions(+), 86 deletions(-) diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 677659ec..72160158 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -3,6 +3,8 @@ package seng302.gameServer; import java.io.IOException; import java.net.ServerSocket; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Random; import java.util.Timer; import java.util.TimerTask; @@ -13,7 +15,6 @@ import seng302.model.GeoPoint; import seng302.model.Player; import seng302.model.PolarTable; import seng302.model.ServerYacht; -import seng302.model.mark.CompoundMark; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.utilities.GeoUtility; @@ -329,39 +330,107 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { * Initialise boats to specific spaced out geopoints behind starting line. */ private void initialiseBoatPositions() { - CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0); - GeoPoint startMark1 = cm.getSubMark(1); - GeoPoint startMark2 = cm.getSubMark(2); +// CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0); +// GeoPoint startMark1 = cm.getSubMark(1); +// GeoPoint startMark2 = cm.getSubMark(2); +// +// // Calculating midpoint +// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2); +// Double length = GeoUtility.getDistance(startMark1, startMark2); +// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2); +// +// // Setting each boats position side by side +// final double SEPARATION = 50.0; // distance apart in meters +// +// int boatIndex = 0; +// for (ServerYacht yacht : GameState.getYachts().values()) { +// int distanceApart = boatIndex / 2; +// +// if (boatIndex % 2 == 1 && boatIndex != 0) { +// distanceApart++; +// distanceApart *= -1; +// } +// +// GeoPoint spawnMark = GeoUtility +// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION); +// +// if (yacht.getHeading() < perpendicularAngle) { +// spawnMark = GeoUtility +// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION); +// } else { +// spawnMark = GeoUtility +// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION); +// } +// +// yacht.setLocation(spawnMark); +// boatIndex++; +// } - // Calculating midpoint - Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2); - Double length = GeoUtility.getDistance(startMark1, startMark2); - GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2); + final double SEPARATION = 50.0; // distance apart in meters - // Setting each boats position side by side - double DISTANCE_FACTOR = 50.0; // distance apart in meters - int boatIndex = 0; - for (ServerYacht yacht : GameState.getYachts().values()) { - int distanceApart = boatIndex / 2; + //Reverse of the angle from start to first mark + double angleToFirstMark = 360 - GeoUtility.getBearing( + GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(), + GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() + ); - if (boatIndex % 2 == 1 && boatIndex != 0) { - distanceApart++; - distanceApart *= -1; + //Length of start line + double startLineLength = GeoUtility.getDistance( + GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), + GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) + ); + + //Angle of start line + double startMarkToMarkAngle = GeoUtility.getBearing( + GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), + GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) + ); + + //How many yachts can fit along the start line + int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION); + //The free space left by the boats. + double buffer = (startLineLength % SEPARATION) / 2; + + //Randomize starting order. + List serverYachtList = new ArrayList<>(GameState.getYachts().values()); + Collections.shuffle(serverYachtList); + + //set the starting point away from start line. + GeoPoint startingPoint = GeoUtility.getGeoCoordinate( + GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), + angleToFirstMark, SEPARATION + ); + + //Move it along the start line + startingPoint = GeoUtility.getGeoCoordinate( + startingPoint, startMarkToMarkAngle, buffer + ); + + int yachtCount = 0; + int repeats = 0; + + GeoPoint yachtLocation; + + for (ServerYacht serverYacht : serverYachtList) { + + //Move away from start line + yachtLocation = GeoUtility.getGeoCoordinate( + startingPoint, angleToFirstMark,repeats * SEPARATION + ); + //Move along start line + yachtLocation = GeoUtility.getGeoCoordinate( + yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION + ); + serverYacht.setLocation(yachtLocation); + serverYacht.setHeading(GeoUtility.getBearing( + yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() + )); + //Set location for next yacht + yachtCount++; + if (yachtCount > spacesAlongLine) { + yachtCount = 0; + repeats++; } - - GeoPoint spawnMark = GeoUtility - .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * DISTANCE_FACTOR); - - if (yacht.getHeading() < perpendicularAngle) { - spawnMark = GeoUtility - .getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCE_FACTOR); - } else { - spawnMark = GeoUtility - .getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCE_FACTOR); - } - - yacht.setLocation(spawnMark); - boatIndex++; } } } diff --git a/src/main/java/seng302/gameServer/MessageFactory.java b/src/main/java/seng302/gameServer/MessageFactory.java index bd30f897..52ab54c6 100644 --- a/src/main/java/seng302/gameServer/MessageFactory.java +++ b/src/main/java/seng302/gameServer/MessageFactory.java @@ -56,7 +56,8 @@ public class MessageFactory { new ArrayList<>(), race.getMarkSequence(), race.getCourseLimit(), - new ArrayList<>(race.getCompoundMarks().values()) + new ArrayList<>(race.getCompoundMarks().values()), + GameState.getCapacity(), true ) ); String xmlStr = xmlGenerator.getRaceAsXml(); diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index 0df0e0fc..dfd8622b 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -15,6 +15,7 @@ import java.util.zip.Checksum; import javafx.beans.property.SimpleObjectProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.ChatterMessage; import seng302.gameServer.messages.ClientType; @@ -196,11 +197,11 @@ public class ServerToClientThread implements Runnable { // TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes. break; case RACE_XML: + Document document = StreamParser.extractXmlMessage(packet); raceXMLProperty.set( - XMLParser.parseRace( - StreamParser.extractXmlMessage(packet) - ) + XMLParser.parseRace(document) ); + GameState.setMaxPlayers(XMLParser.getMaxPlayers(document)); break; case REGATTA_XML: regattaXMLProperty.set( diff --git a/src/main/java/seng302/model/stream/xml/generator/RaceXMLTemplate.java b/src/main/java/seng302/model/stream/xml/generator/RaceXMLTemplate.java index aa958b03..07cb97db 100644 --- a/src/main/java/seng302/model/stream/xml/generator/RaceXMLTemplate.java +++ b/src/main/java/seng302/model/stream/xml/generator/RaceXMLTemplate.java @@ -20,15 +20,19 @@ public class RaceXMLTemplate { private List roundings; private List courseLimit; private List course; + private Integer maxPlayers; + private Boolean tokensEnabled; public RaceXMLTemplate(List yachts, List tokens, List roundings, - List limit, List course) { + List limit, List course, Integer maxPlayers, Boolean tokensEnabled) { this.yachts = yachts; this.tokens = tokens; this.roundings = roundings; this.courseLimit = limit; this.course = course; startTime = LocalDateTime.now(); + this.maxPlayers = maxPlayers; + this.tokensEnabled = tokensEnabled; } /** @@ -83,4 +87,12 @@ public class RaceXMLTemplate { public void setTokens(List tokens) { this.tokens = tokens; } + + public String getTokensEnabled() { + return tokensEnabled.toString(); + } + + public String getMaxPlayers() { + return maxPlayers.toString(); + } } diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index d9dbeef6..7b0ec10e 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -13,6 +13,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -35,6 +36,8 @@ import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; */ public class XMLParser { + private static final int MAX_PLAYERS = 8; + /** * Returns the text content of a given child element tag, assuming it exists, as an Integer. * @@ -45,7 +48,7 @@ public class XMLParser { private static Integer getElementInt(Element ele, String tag) { NodeList tagList = ele.getElementsByTagName(tag); if (tagList.getLength() > 0) { - return Integer.parseInt(tagList.item(0).getTextContent()); + return Integer.parseInt(tagList.item(0).getTextContent().replaceAll("\\s+","")); } else { return null; } @@ -77,7 +80,7 @@ public class XMLParser { private static Double getElementDouble(Element ele, String tag) { NodeList tagList = ele.getElementsByTagName(tag); if (tagList.getLength() > 0) { - return Double.parseDouble(tagList.item(0).getTextContent()); + return Double.parseDouble(tagList.item(0).getTextContent().replaceAll("\\s+","")); } else { return null; } @@ -195,6 +198,31 @@ public class XMLParser { ); } + public static Boolean tokensEnabled(Document doc) { + Element docEle = doc.getDocumentElement(); + try { + Node tokenNode = docEle.getAttributeNode("Tokens"); + return Boolean.valueOf(XMLParser.getNodeAttributeString(tokenNode, "Enabled")); + } catch (NullPointerException npe) { + return false; + } + } + + public static Integer getMaxPlayers(Document doc) { + Element docEle = doc.getDocumentElement(); + try { + NamedNodeMap namedNodeMap = docEle.getElementsByTagName("Participants").item(0).getAttributes(); + Node node = namedNodeMap.getNamedItem("MaxPlayers"); + if (node != null) { + return Integer.parseInt(node.getNodeValue()); + } + } catch (NullPointerException npe) { + npe.printStackTrace(); + return MAX_PLAYERS; + } + return MAX_PLAYERS; + } + /** * Returns an object containing the data extracted from the given xml formatted document * @@ -350,9 +378,13 @@ public class XMLParser { * @param url the location of the race def file * @param serverName the name of the server * @param repetitions the repetitions of a segment of the race def file. + * @param maxPlayers max number of players. uses the default race max if null or greater than the actual max. + * @param tokensEnabled if tokens are enabled * @return a pair which contains regatta string, race string as key, value pair. */ - public static Pair parseRaceDef(String url, String serverName, int repetitions) { + public static Pair parseRaceDef( + String url, String serverName, Integer repetitions, Integer maxPlayers, Boolean tokensEnabled + ) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; Document doc = null; @@ -369,16 +401,25 @@ public class XMLParser { XMLParser.getElementDouble(docEle, "CentralLat"), XMLParser.getElementDouble(docEle, "CentralLng") ); + XMLGenerator xmlGenerator = new XMLGenerator(); xmlGenerator.setRegattaTemplate(regattaXMLTemplate); - RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(new ArrayList<>(), new ArrayList<>(), + if (maxPlayers == null) { + maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers"); + } else if (maxPlayers > XMLParser.getElementInt(docEle, "MaxPlayers")) { + maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers"); + } + + RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate( + new ArrayList<>(), new ArrayList<>(), XMLParser.extractMarkOrderRaceDef(docEle, repetitions), XMLParser.extractCourseLimitRaceDef(docEle), - XMLParser.extractCompoundMarksRaceDef(docEle) + XMLParser.extractCompoundMarksRaceDef(docEle), + maxPlayers, tokensEnabled ); xmlGenerator.setRaceTemplate(raceXMLTemplate); - return new Pair<>(xmlGenerator.getRegattaAsXml(), xmlGenerator.getRaceAsXml()); + return new Pair<>(regattaXMLTemplate, raceXMLTemplate); } private static List extractMarkOrderRaceDef(Element docEle, int repitions){ diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index f7d7695b..c8bb719c 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -30,6 +30,9 @@ import seng302.gameServer.messages.XMLMessage; import seng302.gameServer.messages.XMLMessageSubType; import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.StreamPacket; +import seng302.model.stream.xml.generator.RaceXMLTemplate; +import seng302.model.stream.xml.generator.RegattaXMLTemplate; +import seng302.utilities.XMLGenerator; import seng302.utilities.XMLParser; /** @@ -373,18 +376,23 @@ public class ClientToServerThread implements Runnable { return clientId; } - public void sendXML(String path, String serverName, int legRepeats) { - Pair regattaRace = XMLParser.parseRaceDef(path, serverName, legRepeats); - + public void sendXML(String path, String serverName, Integer legRepeats, Integer maxPlayers, Boolean tokensEnabled) { + Pair regattaRace = XMLParser.parseRaceDef( + path, serverName, legRepeats, maxPlayers, tokensEnabled + ); + XMLGenerator xmlGenerator = new XMLGenerator(); + xmlGenerator.setRegattaTemplate(regattaRace.getKey()); + xmlGenerator.setRaceTemplate(regattaRace.getValue()); + String regatta = xmlGenerator.getRegattaAsXml(); + String race = xmlGenerator.getRaceAsXml(); sendByteBuffer( new XMLMessage( - regattaRace.getKey(), XMLMessageSubType.REGATTA, regattaRace.getKey().length() + regatta, XMLMessageSubType.REGATTA, regatta.length() ).getBuffer() ); - sendByteBuffer( new XMLMessage( - regattaRace.getValue(), XMLMessageSubType.RACE, regattaRace.getValue().length() + race, XMLMessageSubType.RACE, race.length() ).getBuffer() ); } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index b2ade01c..20bf4553 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -122,18 +122,20 @@ public class GameClient { * @param ipAddress IP to connect to. * @param portNumber Port to connect to. */ - public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race, Integer numLegs) { + public ServerDescription runAsHost( + String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race, + Integer numLegs, Boolean tokensEnabled + ) { XMLGenerator.setDefaultRaceName(serverName); server = new MainServerThread(); - GameState.setMaxPlayers(maxPlayers); try { startClientToServerThread(ipAddress, 4942); } catch (IOException e) { showConnectionError("Cannot connect to server as host"); } - socketThread.sendXML(race, serverName, numLegs); + socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled); while (regattaData == null){ try { Thread.sleep(100); diff --git a/src/main/java/seng302/visualiser/MapMaker.java b/src/main/java/seng302/visualiser/MapMaker.java index f0796886..9425bf0a 100644 --- a/src/main/java/seng302/visualiser/MapMaker.java +++ b/src/main/java/seng302/visualiser/MapMaker.java @@ -13,8 +13,11 @@ import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import seng302.model.stream.xml.generator.RaceXMLTemplate; +import seng302.model.stream.xml.generator.RegattaXMLTemplate; import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RegattaXMLData; +import seng302.utilities.XMLGenerator; import seng302.utilities.XMLParser; /** @@ -26,8 +29,10 @@ public class MapMaker { private List races = new ArrayList<>(); private List regattas = new ArrayList<>(); private List filePaths = new ArrayList<>(); + private List maxPlayers = new ArrayList<>(); private static MapMaker instance; private int index = 0; + private XMLGenerator xmlGenerator = new XMLGenerator(); public static MapMaker getInstance() { if (instance == null) { @@ -41,32 +46,39 @@ public class MapMaker { File[] directoryListing = dir.listFiles(); if (directoryListing != null) { for (File child : directoryListing) { - Pair regattaRace = XMLParser.parseRaceDef( - child.getAbsolutePath(), "", 1 + Pair regattaRace = XMLParser.parseRaceDef( + child.getAbsolutePath(), "", 1, null, false ); filePaths.add(child.getAbsolutePath()); + RegattaXMLTemplate regattaTemplate = regattaRace.getKey(); + regattas.add(new RegattaXMLData( + regattaTemplate.getRegattaId(), + regattaTemplate.getName(), + regattaTemplate.getCourseName(), + regattaTemplate.getLatitude(), + regattaTemplate.getLongitude(), + regattaTemplate.getUtcOffset() + )); + + RaceXMLTemplate raceTemplate = regattaRace.getValue(); + xmlGenerator.setRaceTemplate(raceTemplate); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; Document doc = null; try { db = dbf.newDocumentBuilder(); - doc = db.parse(new InputSource(new StringReader(regattaRace.getKey()))); - } catch (ParserConfigurationException | IOException | SAXException e) { - e.printStackTrace(); - } - regattas.add(XMLParser.parseRegatta(doc)); - try { - db = dbf.newDocumentBuilder(); - doc = db.parse(new InputSource(new StringReader(regattaRace.getValue()))); + doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml()))); } catch (ParserConfigurationException | IOException | SAXException e) { e.printStackTrace(); } + RaceXMLData race = XMLParser.parseRace(doc); - MapPreview mapPreview = new MapPreview( + maxPlayers.add(XMLParser.getMaxPlayers(doc)); + + mapPreviews.add(new MapPreview( new ArrayList<>(race.getCompoundMarks().values()), race.getMarkSequence(), race.getCourseLimit() - ); - mapPreviews.add(mapPreview); + )); races.add(race); } } @@ -101,4 +113,8 @@ public class MapMaker { public String getCurrentRacePath() { return filePaths.get(index); } + + public Integer getMaxPlayers() { + return maxPlayers.get(index); + } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java b/src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java index a6d2f1d0..b7d0b38c 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/ServerCreationController.java @@ -10,7 +10,6 @@ import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import seng302.gameServer.ServerDescription; import seng302.utilities.Sounds; @@ -50,13 +49,18 @@ public class ServerCreationController implements Initializable { //---------FXML END---------// public void initialize(URL location, ResourceBundle resources) { - legsSlider.setMax(10); + maxPlayersSlider.valueProperty().addListener( (observable, oldValue, newValue) -> updateMaxPlayerLabel() ); + maxPlayersSlider.setMax(mapMaker.getMaxPlayers()); + maxPlayersSlider.setValue(mapMaker.getMaxPlayers()); + legsSlider.valueProperty().addListener( (obs, oldVal, newVal) -> updateLegSliderLabel() ); + legsSlider.setMax(10); + updateMaxPlayerLabel(); updateLegSliderLabel(); @@ -105,7 +109,7 @@ public class ServerCreationController implements Initializable { private void createServer() { ServerDescription serverDescription = ViewManager.getInstance().getGameClient() .runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider - .getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue()); + .getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected()); ViewManager.getInstance().setProperty("serverName", serverDescription.getName()); ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName()); @@ -127,20 +131,24 @@ public class ServerCreationController implements Initializable { } - public void playButtonHoverSound(MouseEvent mouseEvent) { + public void playButtonHoverSound() { Sounds.playHoverSound(); } private void nextMap() { mapMaker.next(); - mapHolder.getChildren().setAll(mapMaker.getCurrentGameView()); - mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName()); + updateMap(); } private void lastMap() { mapMaker.previous(); - mapHolder.getChildren().setAll(mapMaker.getCurrentGameView()); - mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName()); + updateMap(); } + private void updateMap() { + mapHolder.getChildren().setAll(mapMaker.getCurrentGameView()); + mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName()); + maxPlayersSlider.setMax(mapMaker.getMaxPlayers()); + maxPlayersSlider.setValue(mapMaker.getMaxPlayers()); + } } diff --git a/src/main/resources/maps/default.xml b/src/main/resources/maps/default.xml index 3b91bb3b..5d3da318 100644 --- a/src/main/resources/maps/default.xml +++ b/src/main/resources/maps/default.xml @@ -6,6 +6,8 @@ 57.6679590 11.8503233 + 10 + diff --git a/src/main/resources/maps/horseshoe.xml b/src/main/resources/maps/horseshoe.xml index b917eb32..ee95efb8 100644 --- a/src/main/resources/maps/horseshoe.xml +++ b/src/main/resources/maps/horseshoe.xml @@ -6,6 +6,8 @@ -14.6457 47.612855 + 5 + diff --git a/src/main/resources/server_config/xml_templates/race.ftlh b/src/main/resources/server_config/xml_templates/race.ftlh index aa347423..c9830a9b 100644 --- a/src/main/resources/server_config/xml_templates/race.ftlh +++ b/src/main/resources/server_config/xml_templates/race.ftlh @@ -5,13 +5,13 @@ 15082901 Fleet - + <#list boats as boat> - + <#list tokens as token> diff --git a/src/test/java/seng302/models/MarkOrderTest.java b/src/test/java/seng302/models/MarkOrderTest.java index 13473604..a782d758 100644 --- a/src/test/java/seng302/models/MarkOrderTest.java +++ b/src/test/java/seng302/models/MarkOrderTest.java @@ -4,14 +4,20 @@ import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; +import java.io.IOException; +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import seng302.gameServer.messages.XMLMessageSubType; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import seng302.model.mark.CompoundMark; import seng302.model.mark.MarkOrder; -import seng302.model.stream.packets.StreamPacket; -import seng302.utilities.StreamParser; +import seng302.utilities.XMLGenerator; import seng302.utilities.XMLParser; public class MarkOrderTest { @@ -35,17 +41,22 @@ public class MarkOrderTest { ///-( \' \\ */ - markOrder = new MarkOrder( - XMLParser.parseRace( - StreamParser.extractXmlMessage( - new StreamPacket( - XMLMessageSubType.RACE.getType(), - XMLParser.parseRaceDef("/maps/default.xml", "test", 2).getValue().length(), - 0, XMLParser.parseRaceDef("/maps/default.xml", "test", 2).getValue().getBytes() - ) - ) - ) + XMLGenerator xmlGenerator = new XMLGenerator(); + xmlGenerator.setRaceTemplate( + XMLParser.parseRaceDef( + "/maps/default.xml", "test", 2, null, false + ).getValue() ); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + Document doc = null; + try { + db = dbf.newDocumentBuilder(); + doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml()))); + } catch (ParserConfigurationException | IOException | SAXException e) { + e.printStackTrace(); + } + markOrder = new MarkOrder(XMLParser.parseRace(doc)); currentSeqID = 0; } From e9881bb24adb64a06565c387818e6781cfa90fed Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 27 Sep 2017 02:04:24 +1300 Subject: [PATCH 2/4] Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts. #implement #story[1275] --- .../seng302/gameServer/MainServerThread.java | 145 ++++++++++++------ .../seng302/gameServer/MessageFactory.java | 3 + .../java/seng302/visualiser/GameView3D.java | 4 +- src/main/resources/maps/horseshoe.xml | 4 +- 4 files changed, 109 insertions(+), 47 deletions(-) diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index 72160158..aaabb9c5 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -254,8 +254,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { } }); } else { - serverToClientThread.addConnectionListener(this::sendSetupMessages); MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); + serverToClientThread.addConnectionListener(this::sendSetupMessages); } serverToClientThreads.add(serverToClientThread); serverToClientThread.addDisconnectListener(this::clientDisconnected); @@ -366,13 +366,75 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { // boatIndex++; // } - final double SEPARATION = 50.0; // distance apart in meters +// final double SEPARATION = 50.0; // distance apart in meters +// +// //Reverse of the angle from start to first mark +// double angleToFirstMark = 360 - GeoUtility.getBearing( +// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(), +// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() +// ); +// +// //Length of start line +// double startLineLength = GeoUtility.getDistance( +// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), +// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) +// ); +// +// //Angle of start line +// double startMarkToMarkAngle = GeoUtility.getBearing( +// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), +// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) +// ); +// +// //How many yachts can fit along the start line +// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION); +// //The free space left by the boats. +// double buffer = (startLineLength % SEPARATION) / 2; +// +// //Randomize starting order. +// List serverYachtList = new ArrayList<>(GameState.getYachts().values()); +// Collections.shuffle(serverYachtList); +// +// //set the starting point away from start line. +// GeoPoint startingPoint = GeoUtility.getGeoCoordinate( +// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), +// angleToFirstMark, SEPARATION +// ); +// +// //Move it along the start line +// startingPoint = GeoUtility.getGeoCoordinate( +// startingPoint, startMarkToMarkAngle, buffer +// ); +// +// int yachtCount = 0; +// int repeats = 0; +// +// GeoPoint yachtLocation; +// +// for (ServerYacht serverYacht : serverYachtList) { +// +// //Move away from start line +// yachtLocation = GeoUtility.getGeoCoordinate( +// startingPoint, angleToFirstMark,repeats * SEPARATION +// ); +// //Move along start line +// yachtLocation = GeoUtility.getGeoCoordinate( +// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION +// ); +// serverYacht.setLocation(yachtLocation); +// serverYacht.setHeading(GeoUtility.getBearing( +// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() +// )); +// //Set location for next yacht +// yachtCount++; +// if (yachtCount > spacesAlongLine) { +// yachtCount = 0; +// repeats++; +// } +// } - //Reverse of the angle from start to first mark - double angleToFirstMark = 360 - GeoUtility.getBearing( - GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(), - GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() - ); + final double DISTANCE_TO_START = 75d; + final double YACHT_SEPARATION = 20d; //Length of start line double startLineLength = GeoUtility.getDistance( @@ -380,57 +442,54 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) ); + //How many yachts can fit along the start line + int spacesAlongLine = (int) Math.round(startLineLength / YACHT_SEPARATION); + //Angle of start line double startMarkToMarkAngle = GeoUtility.getBearing( GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2) ); - //How many yachts can fit along the start line - int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION); - //The free space left by the boats. - double buffer = (startLineLength % SEPARATION) / 2; + //angle from first mark to the start + double angleToStart = GeoUtility.getBearing( + GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint(), + GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint() + ); - //Randomize starting order. - List serverYachtList = new ArrayList<>(GameState.getYachts().values()); - Collections.shuffle(serverYachtList); + double angleFromStart = GeoUtility.getBearing( + GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(), + GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() + ); - //set the starting point away from start line. GeoPoint startingPoint = GeoUtility.getGeoCoordinate( - GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1), - angleToFirstMark, SEPARATION + GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(), + angleToStart, DISTANCE_TO_START ); - //Move it along the start line - startingPoint = GeoUtility.getGeoCoordinate( - startingPoint, startMarkToMarkAngle, buffer - ); + List randomisedYachts = new ArrayList<>(GameState.getYachts().values()); + Collections.shuffle(randomisedYachts); + while (randomisedYachts.size() > 0) { - int yachtCount = 0; - int repeats = 0; + int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine; + double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2; - GeoPoint yachtLocation; - - for (ServerYacht serverYacht : serverYachtList) { - - //Move away from start line - yachtLocation = GeoUtility.getGeoCoordinate( - startingPoint, angleToFirstMark,repeats * SEPARATION + GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate( + startingPoint, startMarkToMarkAngle + 180, yachtSpace ); - //Move along start line - yachtLocation = GeoUtility.getGeoCoordinate( - yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION - ); - serverYacht.setLocation(yachtLocation); - serverYacht.setHeading(GeoUtility.getBearing( - yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint() - )); - //Set location for next yacht - yachtCount++; - if (yachtCount > spacesAlongLine) { - yachtCount = 0; - repeats++; + + for (int i=0; i yachts) { + for (ServerYacht serverYacht : yachts) { + System.out.println(serverYacht); + } xmlGenerator.getRace().setBoats(yachts); String xmlStr = xmlGenerator.getBoatsAsXml(); MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length()); diff --git a/src/main/java/seng302/visualiser/GameView3D.java b/src/main/java/seng302/visualiser/GameView3D.java index f397b06b..e54776ba 100644 --- a/src/main/java/seng302/visualiser/GameView3D.java +++ b/src/main/java/seng302/visualiser/GameView3D.java @@ -2,7 +2,6 @@ package seng302.visualiser; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,7 +23,6 @@ import javafx.scene.transform.Translate; import seng302.gameServer.messages.RoundingSide; import seng302.model.ClientYacht; import seng302.model.GameKeyBind; -import seng302.model.GeoPoint; import seng302.model.KeyAction; import seng302.model.Limit; import seng302.model.ScaledPoint; @@ -79,6 +77,8 @@ public class GameView3D extends GameView{ topDownCam = new TopDownCamera(); chaseCam = new ChaseCamera(); + canvasWidth = canvasHeight = 300; + for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) { pc.setFarClip(600); pc.setNearClip(0.1); diff --git a/src/main/resources/maps/horseshoe.xml b/src/main/resources/maps/horseshoe.xml index ee95efb8..4c43f86e 100644 --- a/src/main/resources/maps/horseshoe.xml +++ b/src/main/resources/maps/horseshoe.xml @@ -11,7 +11,7 @@ - + @@ -63,7 +63,7 @@ - + From b18d9e85736be6bd29cc1268cdbe1a3d8ca4a84e Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 27 Sep 2017 02:04:58 +1300 Subject: [PATCH 3/4] Added empty cucumber #test --- .../java/seng302/visualiser/GameView.java | 2 +- src/test/java/features/CustomMaps.feature | 17 +++++ src/test/java/steps/CustomMapsSteps.java | 69 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/test/java/features/CustomMaps.feature create mode 100644 src/test/java/steps/CustomMapsSteps.java diff --git a/src/main/java/seng302/visualiser/GameView.java b/src/main/java/seng302/visualiser/GameView.java index e0d62a5d..bc8ea0b9 100644 --- a/src/main/java/seng302/visualiser/GameView.java +++ b/src/main/java/seng302/visualiser/GameView.java @@ -10,7 +10,7 @@ import seng302.model.mark.CompoundMark; import seng302.model.mark.Corner; /** - * Created by cir27 on 26/09/17. + * Common elements of game visualizing classes. */ public abstract class GameView { diff --git a/src/test/java/features/CustomMaps.feature b/src/test/java/features/CustomMaps.feature new file mode 100644 index 00000000..1dd403ed --- /dev/null +++ b/src/test/java/features/CustomMaps.feature @@ -0,0 +1,17 @@ +Feature: Multiple Maps + + Scenario: + Given that the game has multiple race xml files + Then all of them can be seen + + Scenario: + Given that I choose a race + Then that race's course is received by clients + + Scenario: + Given that I choose a name for the server + Then that name is sent to the client + + Scenario: + Given that the client has received a race + Then the name of that race shown to the host is the course name \ No newline at end of file diff --git a/src/test/java/steps/CustomMapsSteps.java b/src/test/java/steps/CustomMapsSteps.java new file mode 100644 index 00000000..42e9314b --- /dev/null +++ b/src/test/java/steps/CustomMapsSteps.java @@ -0,0 +1,69 @@ +package steps; + +import cucumber.api.java.en.Given; +import cucumber.api.java.en.Then; +import java.io.File; +import org.junit.Assert; +import seng302.visualiser.MapMaker; + +/** + * Created by cir27 on 26/09/17. + */ +public class CustomMapsSteps { + + MapMaker mapMaker; + + + @Given("^that the game has multiple race xml files$") + public void that_the_game_has_multiple_race_xml_files() throws Throwable { + mapMaker = MapMaker.getInstance(); + String firstMap = mapMaker.getCurrentRacePath(); + int numMaps = 0; + do { + mapMaker.next(); + numMaps++; + } while (!mapMaker.getCurrentRacePath().equals(firstMap)); + Assert.assertTrue(numMaps >= 2); + } + + @Then("^all of them can be seen$") + public void all_of_them_can_be_seen() throws Throwable { + File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles(); + for (File file : files) { + if (file.isFile()) { + Assert.assertTrue(file.getAbsolutePath().equals(mapMaker.getCurrentRacePath())); + mapMaker.next(); + System.out.println(file.getAbsolutePath()); + } + } + } + + @Given("^that I choose a race$") + public void that_I_choose_a_race() throws Throwable { + + } + + @Then("^that race's course is received by clients$") + public void that_race_s_course_is_received_by_clients() throws Throwable { + + } + + @Given("^that I choose a name for the server$") + public void that_I_choose_a_name_for_the_server() throws Throwable { + + } + + @Then("^that name is sent to the client$") + public void that_name_is_sent_to_the_client() throws Throwable { + + } + + @Given("^that the client has received a race$") + public void that_the_client_has_received_a_race() throws Throwable { + } + + @Then("^the name of that race shown to the host is the course name$") + public void the_name_of_that_race_shown_to_the_host_is_the_course_name() throws Throwable { + + } +} From c0bd498f1bf9e9049dba13f58db3fbb83343c142 Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 27 Sep 2017 02:50:36 +1300 Subject: [PATCH 4/4] Added debugs for missing xml --- .../java/seng302/gameServer/GameState.java | 1 + .../seng302/gameServer/MainServerThread.java | 21 ++++++++++++++----- .../gameServer/ServerToClientThread.java | 6 ++++-- .../java/seng302/utilities/StreamParser.java | 2 +- .../java/seng302/visualiser/GameClient.java | 1 + 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 6eccd2ca..28935621 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -438,6 +438,7 @@ public class GameState implements Runnable { serverYacht.powerUp(collidedToken.getTokenType()); logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken .getTokenType()); + System.out.println("AGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"); notifyMessageListeners(MessageFactory.getRaceXML()); notifyMessageListeners( new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN)); diff --git a/src/main/java/seng302/gameServer/MainServerThread.java b/src/main/java/seng302/gameServer/MainServerThread.java index aaabb9c5..535ff03e 100644 --- a/src/main/java/seng302/gameServer/MainServerThread.java +++ b/src/main/java/seng302/gameServer/MainServerThread.java @@ -42,6 +42,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { private static Integer capacity; private RaceXMLData raceXMLData; private RegattaXMLData regattaXMLData; + private boolean serverStarted = false; private void startAdvertisingServer() { Integer capacity = GameState.getCapacity(); @@ -83,10 +84,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { GameState.setRace(raceXMLData); MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); startAdvertisingServer(); - PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv")); + PolarTable + .parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv")); GameState.addMessageEventListener(this::broadcastMessage); startUpdatingWind(); startSpawningTokens(); + System.out.println("SAAAANNNNNNNNNDDDDDDDDDDDDDDDDDDDDDDDDDDdd"); sendSetupMessages(); } @@ -101,6 +104,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { for (ServerToClientThread stc : serverToClientThreads) { if (!stc.isSocketOpen()) { GameState.getYachts().remove(stc.getSourceId()); + System.out.println("AAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); sendSetupMessages(); try { stc.getSocket().close(); @@ -118,6 +122,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { } if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) { MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); + System.out.println("gfdgfdgfdg"); sendSetupMessages(); GameState.resetCustomizationFlag(); } @@ -255,7 +260,13 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { }); } else { MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values())); - serverToClientThread.addConnectionListener(this::sendSetupMessages); + for (ServerYacht serverYacht : GameState.getYachts().values()) { + System.out.println("Connecterino" + serverYacht); + } + serverToClientThread.addConnectionListener(() -> { + System.out.println("LUSTENER"); + sendSetupMessages(); + }); } serverToClientThreads.add(serverToClientThread); serverToClientThread.addDisconnectListener(this::clientDisconnected); @@ -317,9 +328,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate { }, 0, 500); - if (GameState.getCurrentStage() == GameStages.LOBBYING) { - sendSetupMessages(); - } +// if (GameState.getCurrentStage() == GameStages.LOBBYING) { +// sendSetupMessages(); +// } } public void terminate() { diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java index dfd8622b..07257a30 100644 --- a/src/main/java/seng302/gameServer/ServerToClientThread.java +++ b/src/main/java/seng302/gameServer/ServerToClientThread.java @@ -108,10 +108,11 @@ public class ServerToClientThread implements Runnable { ServerYacht yacht = new ServerYacht( BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ" ); - + System.out.println(yacht); player = new Player(socket, yacht); GameState.addYacht(sourceId, yacht); GameState.addPlayer(player); + System.out.println(GameState.getYachts().size()); } private void completeRegistration(ClientType clientType) throws IOException { @@ -135,8 +136,9 @@ public class ServerToClientThread implements Runnable { this.sourceId = sourceId; isRegistered = true; os.write(responseMessage.getBuffer()); - + System.out.println("MAKING A PLAYER"); setUpPlayer(); + System.out.println("DONE MAKING A PLAYER"); for (ConnectionListener listener : connectionListeners) { listener.notifyConnection(); diff --git a/src/main/java/seng302/utilities/StreamParser.java b/src/main/java/seng302/utilities/StreamParser.java index 5672fdf5..0b9a210a 100644 --- a/src/main/java/seng302/utilities/StreamParser.java +++ b/src/main/java/seng302/utilities/StreamParser.java @@ -136,7 +136,7 @@ public class StreamParser { long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); String xmlMessage = new String( (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); - + System.out.println(xmlMessage); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 938e998e..4953a049 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -214,6 +214,7 @@ public class GameClient { break; case RACE_XML: + System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString()); RaceXMLData raceXMLData = XMLParser.parseRace( StreamParser.extractXmlMessage(packet) );