From ec58f0c847a3cdba2a1b8c76c5ae92060d1afc0e Mon Sep 17 00:00:00 2001 From: fjc40 Date: Sat, 2 Sep 2017 00:27:44 +1200 Subject: [PATCH] Participants can now join during the warning period as well. Added RaceDataSourceToXML. RaceServer now create an XMLMessage when the race's RaceDataSource changes. #story[1188] --- .../src/main/java/mock/app/Event.java | 14 -- .../java/mock/model/ClientConnection.java | 11 +- .../src/main/java/mock/model/RaceLogic.java | 4 +- .../src/main/java/mock/model/RaceServer.java | 30 ++-- .../java/mock/model/SourceIdAllocator.java | 3 +- .../network/Messages/Enums/RaceTypeEnum.java | 12 ++ .../java/shared/dataInput/BoatDataSource.java | 12 ++ .../java/shared/dataInput/BoatXMLReader.java | 13 ++ .../shared/dataInput/EmptyBoatDataSource.java | 13 ++ .../shared/dataInput/EmptyRaceDataSource.java | 13 ++ .../dataInput/EmptyRegattaDataSource.java | 13 ++ .../java/shared/dataInput/RaceDataSource.java | 8 ++ .../java/shared/dataInput/RaceXMLReader.java | 6 +- .../shared/dataInput/RegattaDataSource.java | 10 ++ .../shared/dataInput/RegattaXMLReader.java | 12 ++ .../main/java/shared/enums/RoundingType.java | 15 ++ .../shared/xml/Race/RaceDataSourceToXML.java | 131 ++++++++++++++++++ .../main/resources/mock/mockXML/boatTest.xml | 1 - 18 files changed, 289 insertions(+), 32 deletions(-) create mode 100644 racevisionGame/src/main/java/shared/xml/Race/RaceDataSourceToXML.java diff --git a/racevisionGame/src/main/java/mock/app/Event.java b/racevisionGame/src/main/java/mock/app/Event.java index 27e2103c..dcc5b407 100644 --- a/racevisionGame/src/main/java/mock/app/Event.java +++ b/racevisionGame/src/main/java/mock/app/Event.java @@ -161,8 +161,6 @@ public class Event { this.connectionThread = new Thread(connectionAcceptor, "Event.Start()->ConnectionAcceptor thread"); connectionThread.start(); - sendXMLs(); - } @@ -175,18 +173,6 @@ public class Event { - /** - * Sends out each xml string, via the mock output - */ - private void sendXMLs() { - - connectionAcceptor.setRegattaXml(regattaXML); - - connectionAcceptor.setRaceXml(raceXML); - - connectionAcceptor.setBoatsXml(boatXML); - } - //TODO remove this after demo on 18th august! /** diff --git a/racevisionGame/src/main/java/mock/model/ClientConnection.java b/racevisionGame/src/main/java/mock/model/ClientConnection.java index d2ca7609..2b0caacf 100644 --- a/racevisionGame/src/main/java/mock/model/ClientConnection.java +++ b/racevisionGame/src/main/java/mock/model/ClientConnection.java @@ -109,6 +109,11 @@ public class ClientConnection implements Runnable { */ private ConnectionStateEnum connectionState = ConnectionStateEnum.UNKNOWN; + /** + * The source ID that has been allocated to the client. + * 0 means not allocated. + */ + private int allocatedSourceID = 0; @@ -178,7 +183,7 @@ public class ClientConnection implements Runnable { RequestToJoin requestToJoin = waitForRequestToJoin(); - int allocatedSourceID = 0; + allocatedSourceID = 0; //If they want to participate, give them a source ID number. if (requestToJoin.getRequestType() == RequestToJoinEnum.PARTICIPANT) { @@ -283,6 +288,10 @@ public class ClientConnection implements Runnable { if (this.controllerServerThread != null) { this.controllerServerThread.interrupt(); } + + if (allocatedSourceID != 0) { + sourceIdAllocator.returnSourceID(allocatedSourceID); + } } } diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index a1bddd9a..d1ef39e0 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -71,7 +71,8 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { long previousFrameTime = System.currentTimeMillis(); while (((race.getRaceStatusEnum() == RaceStatusEnum.PRESTART) - || (race.getRaceStatusEnum() == RaceStatusEnum.NOT_ACTIVE)) && loopBool) { + || (race.getRaceStatusEnum() == RaceStatusEnum.NOT_ACTIVE) + || (race.getRaceStatusEnum() == RaceStatusEnum.WARNING)) && loopBool) { long currentTime = System.currentTimeMillis(); @@ -87,6 +88,7 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { //Parse the race snapshot. server.parseSnapshot(); + waitForFramePeriod(previousFrameTime, currentTime, 50); previousFrameTime = currentTime; } diff --git a/racevisionGame/src/main/java/mock/model/RaceServer.java b/racevisionGame/src/main/java/mock/model/RaceServer.java index 45a4f6e0..37c21194 100644 --- a/racevisionGame/src/main/java/mock/model/RaceServer.java +++ b/racevisionGame/src/main/java/mock/model/RaceServer.java @@ -7,9 +7,15 @@ import network.Messages.Enums.XMLMessageType; import shared.model.Bearing; import shared.model.CompoundMark; import shared.model.Mark; +import shared.xml.Race.RaceDataSourceToXML; +import shared.xml.boats.BoatDataSourceToXML; +import shared.xml.regatta.RegattaDataSourceToXML; +import javax.xml.bind.JAXBException; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Created by connortaylorbrown on 2/08/17. @@ -27,26 +33,22 @@ public class RaceServer { /** * The sequence number of race XML messages. */ - private int raceXMLSeqNumber; + private int raceXMLSeqNumber = -1; /** * The sequence number of boat XML messages. */ - private int boatXMLSeqNumber; + private int boatXMLSeqNumber = -1; /** * The sequence number of regatta XML messages. */ - private int regattaXMLSeqNumber; + private int regattaXMLSeqNumber = -1; public RaceServer(MockRace race, LatestMessages latestMessages) { this.race = race; this.latestMessages = latestMessages; - - this.raceXMLSeqNumber = race.getRaceDataSource().getSequenceNumber(); - //this.boatXMLSeqNumber = race.getBoatDataSource().getSequenceNumber(); - //this.regattaXMLSeqNumber = race.getRegattaDataSource().getSequenceNumber(); } /** @@ -85,11 +87,17 @@ public class RaceServer { */ private void updateRaceXMLFile() { if (raceXMLSeqNumber != race.getRaceDataSource().getSequenceNumber()) { - //TODO generate XML string from race data source - String raceXMLString = "test";//TODO - XMLMessage message = createXMLMessage(raceXMLString, XMLMessageType.RACE); - latestMessages.setXMLMessage(message); + raceXMLSeqNumber = race.getRaceDataSource().getSequenceNumber(); + try { + String raceXMLString = RaceDataSourceToXML.toString(race.getRaceDataSource()); + XMLMessage message = createXMLMessage(raceXMLString, XMLMessageType.RACE); + latestMessages.setXMLMessage(message); + + } catch (JAXBException e) { + Logger.getGlobal().log(Level.WARNING, "Could not serialise: " + race.getRaceDataSource(), e); + } + } } diff --git a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java index b609e5a5..17a7e85f 100644 --- a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java +++ b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java @@ -36,7 +36,8 @@ public class SourceIdAllocator { */ public synchronized int allocateSourceID() throws SourceIDAllocationException { - if (mockRace.getRaceStatusEnum() != RaceStatusEnum.PRESTART) { + if (!((mockRace.getRaceStatusEnum() == RaceStatusEnum.PRESTART) + || (mockRace.getRaceStatusEnum() == RaceStatusEnum.WARNING))) { throw new SourceIDAllocationException("Could not allocate a source ID. Can only allocate during pre-start period. It is currently: " + mockRace.getRaceStatusEnum()); } diff --git a/racevisionGame/src/main/java/network/Messages/Enums/RaceTypeEnum.java b/racevisionGame/src/main/java/network/Messages/Enums/RaceTypeEnum.java index 6a03b37e..4c75cc52 100644 --- a/racevisionGame/src/main/java/network/Messages/Enums/RaceTypeEnum.java +++ b/racevisionGame/src/main/java/network/Messages/Enums/RaceTypeEnum.java @@ -71,6 +71,8 @@ public enum RaceTypeEnum { } + + /** * Stores a mapping between Byte values and RaceStatusEnum values. */ @@ -107,4 +109,14 @@ public enum RaceTypeEnum { } + @Override + public String toString() { + if (fromByte(value) == FLEET_RACE) { + return "fleet"; + } else if (fromByte(value) == MATCH_RACE) { + return "match"; + } else { + return super.toString(); + } + } } diff --git a/racevisionGame/src/main/java/shared/dataInput/BoatDataSource.java b/racevisionGame/src/main/java/shared/dataInput/BoatDataSource.java index 40f12c75..17bb7c45 100644 --- a/racevisionGame/src/main/java/shared/dataInput/BoatDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/BoatDataSource.java @@ -22,4 +22,16 @@ public interface BoatDataSource { * @return Map between source ID and mark. */ Map getMarkerBoats(); + + + /** + * Returns the sequence number associated with this data source. Used to indicate when it has changed. + * @return Sequence number. + */ + int getSequenceNumber(); + + /** + * Increments the sequence number for this data source. Used to indicate that it has changed. + */ + void incrementSequenceNumber(); } diff --git a/racevisionGame/src/main/java/shared/dataInput/BoatXMLReader.java b/racevisionGame/src/main/java/shared/dataInput/BoatXMLReader.java index 885309c0..25c956d9 100644 --- a/racevisionGame/src/main/java/shared/dataInput/BoatXMLReader.java +++ b/racevisionGame/src/main/java/shared/dataInput/BoatXMLReader.java @@ -29,6 +29,8 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource { private final Map markerMap = new HashMap<>(); + private int sequenceNumber = 0; + /** * Constructor for Boat XML using a file. * @@ -174,4 +176,15 @@ public class BoatXMLReader extends XMLReader implements BoatDataSource { public Map getMarkerBoats() { return markerMap; } + + + @Override + public int getSequenceNumber() { + return sequenceNumber; + } + + @Override + public void incrementSequenceNumber() { + sequenceNumber++; + } } diff --git a/racevisionGame/src/main/java/shared/dataInput/EmptyBoatDataSource.java b/racevisionGame/src/main/java/shared/dataInput/EmptyBoatDataSource.java index 1de4251e..7a8d2151 100644 --- a/racevisionGame/src/main/java/shared/dataInput/EmptyBoatDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/EmptyBoatDataSource.java @@ -22,6 +22,8 @@ public class EmptyBoatDataSource implements BoatDataSource { private final Map markerMap = new HashMap<>(); + private int sequenceNumber = 0; + public EmptyBoatDataSource() { } @@ -44,4 +46,15 @@ public class EmptyBoatDataSource implements BoatDataSource { public Map getMarkerBoats() { return markerMap; } + + + @Override + public int getSequenceNumber() { + return sequenceNumber; + } + + @Override + public void incrementSequenceNumber() { + sequenceNumber++; + } } diff --git a/racevisionGame/src/main/java/shared/dataInput/EmptyRaceDataSource.java b/racevisionGame/src/main/java/shared/dataInput/EmptyRaceDataSource.java index ffacaa93..676d7e70 100644 --- a/racevisionGame/src/main/java/shared/dataInput/EmptyRaceDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/EmptyRaceDataSource.java @@ -2,8 +2,10 @@ package shared.dataInput; import network.Messages.Enums.RaceTypeEnum; import shared.model.CompoundMark; +import shared.model.Corner; import shared.model.GPSCoordinate; import shared.model.Leg; +import shared.xml.Race.XMLCorner; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -48,6 +50,12 @@ public class EmptyRaceDataSource implements RaceDataSource { */ private final List legs = new ArrayList<>(); + /** + * Corners in race. + */ + private final List corners = new ArrayList<>(); + + /** * The time that the race.xml file was created. @@ -100,6 +108,11 @@ public class EmptyRaceDataSource implements RaceDataSource { return legs; } + @Override + public List getCorners() { + return corners; + } + public List getCompoundMarks() { return new ArrayList<>(compoundMarkMap.values()); } diff --git a/racevisionGame/src/main/java/shared/dataInput/EmptyRegattaDataSource.java b/racevisionGame/src/main/java/shared/dataInput/EmptyRegattaDataSource.java index 05a0fcf9..1546972e 100644 --- a/racevisionGame/src/main/java/shared/dataInput/EmptyRegattaDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/EmptyRegattaDataSource.java @@ -60,6 +60,8 @@ public class EmptyRegattaDataSource implements RegattaDataSource { + private int sequenceNumber = 0; + public EmptyRegattaDataSource() { } @@ -119,4 +121,15 @@ public class EmptyRegattaDataSource implements RegattaDataSource { public GPSCoordinate getGPSCoordinate() { return new GPSCoordinate(centralLatitude, centralLongitude); } + + + @Override + public int getSequenceNumber() { + return sequenceNumber; + } + + @Override + public void incrementSequenceNumber() { + sequenceNumber++; + } } diff --git a/racevisionGame/src/main/java/shared/dataInput/RaceDataSource.java b/racevisionGame/src/main/java/shared/dataInput/RaceDataSource.java index c1a4b370..765098f2 100644 --- a/racevisionGame/src/main/java/shared/dataInput/RaceDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/RaceDataSource.java @@ -2,8 +2,10 @@ package shared.dataInput; import network.Messages.Enums.RaceTypeEnum; import shared.model.CompoundMark; +import shared.model.Corner; import shared.model.GPSCoordinate; import shared.model.Leg; +import shared.xml.Race.XMLCorner; import java.time.ZonedDateTime; import java.util.List; @@ -27,6 +29,12 @@ public interface RaceDataSource { */ List getLegs(); + /** + * Returns the list of corners in the race - two adjacent corners form a leg. + * @return List of corners in race. + */ + List getCorners(); + /** * Returns a list of coordinates representing the boundary of the race. * @return The boundary of the race. diff --git a/racevisionGame/src/main/java/shared/dataInput/RaceXMLReader.java b/racevisionGame/src/main/java/shared/dataInput/RaceXMLReader.java index 6165bf44..41d60e5f 100644 --- a/racevisionGame/src/main/java/shared/dataInput/RaceXMLReader.java +++ b/racevisionGame/src/main/java/shared/dataInput/RaceXMLReader.java @@ -345,7 +345,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { int cornerSeq = Integer.parseInt(getAttribute(cornerElement, "SeqID")); - cornersList.add(new Corner(cornerID, cornerSeq, "SP", 3)); + cornersList.add(new Corner(cornerID, cornerSeq, cornerRounding, 3)); //Gets the CompoundMark associated with this corner. CompoundMark lastCompoundMark = this.compoundMarkMap.get(cornerID); @@ -368,7 +368,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { cornerSeq = Integer.parseInt(getAttribute(cornerElement, "SeqID")); - cornersList.add(new Corner(cornerID, cornerSeq, "Port", 3)); + cornersList.add(new Corner(cornerID, cornerSeq, getCompoundMarkRounding(cornerElement), 3)); //gets the Rounding of this corner element cornerRounding = getCompoundMarkRounding(cornerElement); @@ -490,7 +490,7 @@ public class RaceXMLReader extends XMLReader implements RaceDataSource { return participants; } - public List getCornersList() { + public List getCorners() { return cornersList; } diff --git a/racevisionGame/src/main/java/shared/dataInput/RegattaDataSource.java b/racevisionGame/src/main/java/shared/dataInput/RegattaDataSource.java index eb198cb2..9af55217 100644 --- a/racevisionGame/src/main/java/shared/dataInput/RegattaDataSource.java +++ b/racevisionGame/src/main/java/shared/dataInput/RegattaDataSource.java @@ -66,5 +66,15 @@ public interface RegattaDataSource { float getMagneticVariation(); + /** + * Returns the sequence number associated with this data source. Used to indicate when it has changed. + * @return Sequence number. + */ + int getSequenceNumber(); + + /** + * Increments the sequence number for this data source. Used to indicate that it has changed. + */ + void incrementSequenceNumber(); } diff --git a/racevisionGame/src/main/java/shared/dataInput/RegattaXMLReader.java b/racevisionGame/src/main/java/shared/dataInput/RegattaXMLReader.java index 0a756b03..36743105 100644 --- a/racevisionGame/src/main/java/shared/dataInput/RegattaXMLReader.java +++ b/racevisionGame/src/main/java/shared/dataInput/RegattaXMLReader.java @@ -59,6 +59,8 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource { private float magneticVariation; + private int sequenceNumber = 0; + /** * Constructor for Regatta XML using a file. @@ -209,4 +211,14 @@ public class RegattaXMLReader extends XMLReader implements RegattaDataSource { public GPSCoordinate getGPSCoordinate() { return new GPSCoordinate(centralLatitude, centralLongitude); } + + @Override + public int getSequenceNumber() { + return sequenceNumber; + } + + @Override + public void incrementSequenceNumber() { + sequenceNumber++; + } } diff --git a/racevisionGame/src/main/java/shared/enums/RoundingType.java b/racevisionGame/src/main/java/shared/enums/RoundingType.java index 8f8e719a..e9faef80 100644 --- a/racevisionGame/src/main/java/shared/enums/RoundingType.java +++ b/racevisionGame/src/main/java/shared/enums/RoundingType.java @@ -46,4 +46,19 @@ public enum RoundingType { return null; } } + + public static String getStringOf(RoundingType value) { + switch (value) { + case Port: + return "Port"; + case Starboard: + return "Starboard"; + case SP: + return "SP"; + case PS: + return "PS"; + default: + return null; + } + } } diff --git a/racevisionGame/src/main/java/shared/xml/Race/RaceDataSourceToXML.java b/racevisionGame/src/main/java/shared/xml/Race/RaceDataSourceToXML.java new file mode 100644 index 00000000..3e3b5f8c --- /dev/null +++ b/racevisionGame/src/main/java/shared/xml/Race/RaceDataSourceToXML.java @@ -0,0 +1,131 @@ +package shared.xml.Race; + +import shared.dataInput.RaceDataSource; +import shared.enums.RoundingType; +import shared.model.CompoundMark; +import shared.model.Corner; +import shared.model.GPSCoordinate; +import shared.model.Leg; +import shared.xml.XMLUtilities; + +import javax.xml.bind.JAXBException; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; + +/** + * Has functions to convert a {@link shared.dataInput.RaceDataSource} to an {@link XMLRace} object. + */ +public class RaceDataSourceToXML { + + + /** + * Converts a race data source to an XMLRace object. + * @param raceDataSource The data source to convert. + * @return The XMLRace file. + */ + public static XMLRace toXML(RaceDataSource raceDataSource) { + + //Kind of ugly. Could be refactored/split up a bit. + + + XMLRace race = new XMLRace(); + + + race.setRaceID(raceDataSource.getRaceId()); + race.setRaceType(raceDataSource.getRaceType().toString()); + + + race.setCreationTimeDate(raceDataSource.getCreationDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"))); + + + XMLRaceStartTime startTime = new XMLRaceStartTime(); + startTime.setPostpone(String.valueOf(raceDataSource.getPostponed())); + startTime.setTime(raceDataSource.getStartDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"))); + race.setRaceStartTime(startTime); + + + XMLParticipants participants = new XMLParticipants(); + participants.yacht = new ArrayList<>(); + for (int i : raceDataSource.getParticipants()) { + XMLYacht yacht = new XMLYacht(); + yacht.setSourceID(i); + participants.yacht.add(yacht); + } + race.setParticipants(participants); + + + XMLCourseLimit courseLimit = new XMLCourseLimit(); + courseLimit.limit = new ArrayList<>(); + for (int i = 0; i < raceDataSource.getBoundary().size(); i++) { + XMLLimit limit = new XMLLimit(); + limit.setLat(raceDataSource.getBoundary().get(i).getLatitude()); + limit.setLon(raceDataSource.getBoundary().get(i).getLongitude()); + limit.setSeqID(i + 1); + courseLimit.limit.add(limit); + } + race.setCourseLimit(courseLimit); + + + XMLCourse course = new XMLCourse(); + course.compoundMark = new ArrayList<>(); + for (CompoundMark compoundMark : raceDataSource.getCompoundMarks()) { + XMLCompoundMark xmlCompoundMark = new XMLCompoundMark(); + xmlCompoundMark.setCompoundMarkID(compoundMark.getCompoundMarkID()); + xmlCompoundMark.setName(compoundMark.getName()); + + if (compoundMark.getMark1() != null) { + XMLMark xmlMark = new XMLMark(); + xmlMark.setName(compoundMark.getMark1().getName()); + xmlMark.setSourceID(compoundMark.getMark1().getSourceID()); + xmlMark.setSeqId(1); + xmlMark.setTargetLat(compoundMark.getMark1().getPosition().getLatitude()); + xmlMark.setTargetLng(compoundMark.getMark1().getPosition().getLongitude()); + + xmlCompoundMark.getMark().add(xmlMark); + } + if (compoundMark.getMark2() != null) { + XMLMark xmlMark = new XMLMark(); + xmlMark.setName(compoundMark.getMark2().getName()); + xmlMark.setSourceID(compoundMark.getMark2().getSourceID()); + xmlMark.setSeqId(2); + xmlMark.setTargetLat(compoundMark.getMark2().getPosition().getLatitude()); + xmlMark.setTargetLng(compoundMark.getMark2().getPosition().getLongitude()); + + xmlCompoundMark.getMark().add(xmlMark); + } + + course.compoundMark.add(xmlCompoundMark); + } + race.setCourse(course); + + XMLCompoundMarkSequence compoundMarkSequence = new XMLCompoundMarkSequence(); + compoundMarkSequence.corner = new ArrayList<>(); + for (Corner corner : raceDataSource.getCorners()) { + XMLCorner xmlCorner = new XMLCorner(); + xmlCorner.setZoneSize(corner.getZoneSize()); + xmlCorner.setSeqID(corner.getSeqID()); + xmlCorner.setCompoundMarkID(corner.getCompoundMarkID()); + xmlCorner.setRounding(corner.getRounding()); + + compoundMarkSequence.corner.add(xmlCorner); + } + race.setCompoundMarkSequence(compoundMarkSequence); + + + return race; + } + + + /** + * Converts a race data source to an xml string. + * @param raceDataSource Data source to convert. + * @return String containing xml file. + * @throws JAXBException Thrown if it cannot be converted. + */ + public static String toString(RaceDataSource raceDataSource) throws JAXBException { + XMLRace race = toXML(raceDataSource); + return XMLUtilities.classToXML(race); + } + + +} diff --git a/racevisionGame/src/main/resources/mock/mockXML/boatTest.xml b/racevisionGame/src/main/resources/mock/mockXML/boatTest.xml index 9295dc07..59e2f79d 100644 --- a/racevisionGame/src/main/resources/mock/mockXML/boatTest.xml +++ b/racevisionGame/src/main/resources/mock/mockXML/boatTest.xml @@ -32,7 +32,6 @@ -