From d0eebcdb2f86ab03c3af53f43124068e706e660d Mon Sep 17 00:00:00 2001 From: fjc40 Date: Fri, 1 Sep 2017 01:14:43 +1200 Subject: [PATCH] SourceIdAllocator now allocates from the BoatDataSource and RaceDataSource exposed by MockRace, instead of having its own source IDs. Can only allocate ids during PRESTART period. RaceLogic now calls MockRace.initialiseBoats() after the prestart period has finished. MockRace create a VisualiserBoat when a source ID is allocated. MockOutput now sends updated XML messages during the race, instead of only at the start. #story[1188] --- .../src/main/java/mock/app/MockOutput.java | 24 +++++++-- .../src/main/java/mock/model/MockRace.java | 51 +++++++++++-------- .../src/main/java/mock/model/RaceLogic.java | 32 ++++++++++++ .../java/mock/model/SourceIdAllocator.java | 39 +++++++------- .../src/main/java/shared/model/RaceState.java | 15 +++++- 5 files changed, 117 insertions(+), 44 deletions(-) diff --git a/racevisionGame/src/main/java/mock/app/MockOutput.java b/racevisionGame/src/main/java/mock/app/MockOutput.java index 68136ea0..023235cc 100644 --- a/racevisionGame/src/main/java/mock/app/MockOutput.java +++ b/racevisionGame/src/main/java/mock/app/MockOutput.java @@ -27,7 +27,12 @@ public class MockOutput implements RunnableWithFramePeriod { */ private LatestMessages latestMessages; + //These sequence number track the last race/boat/regatta xml message we've sent. + private int lastSentRaceNumber = -1; + private int lastSentBoatNumber = -1; + + private int lastSentRegattaNumber = -1; @@ -69,7 +74,6 @@ public class MockOutput implements RunnableWithFramePeriod { long previousFrameTime = System.currentTimeMillis(); - boolean sentXMLs = false; @@ -82,16 +86,26 @@ public class MockOutput implements RunnableWithFramePeriod { previousFrameTime = currentFrameTime; - //Send XML messages. - if (!sentXMLs) { + //Send XML messages if needed. + + if (lastSentRaceNumber != latestMessages.getRaceXMLMessage().getSequenceNumber()) { + lastSentRaceNumber = latestMessages.getRaceXMLMessage().getSequenceNumber(); outgoingMessages.put(latestMessages.getRaceXMLMessage()); - outgoingMessages.put(latestMessages.getRegattaXMLMessage()); + } + + if (lastSentBoatNumber != latestMessages.getBoatXMLMessage().getSequenceNumber()) { + lastSentBoatNumber = latestMessages.getBoatXMLMessage().getSequenceNumber(); outgoingMessages.put(latestMessages.getBoatXMLMessage()); + } - sentXMLs = true; + if (lastSentRegattaNumber != latestMessages.getRegattaXMLMessage().getSequenceNumber()) { + lastSentRegattaNumber = latestMessages.getRegattaXMLMessage().getSequenceNumber(); + outgoingMessages.put(latestMessages.getRegattaXMLMessage()); } + + List snapshot = latestMessages.getSnapshot(); for (AC35Data message : snapshot) { outgoingMessages.put(message); diff --git a/racevisionGame/src/main/java/mock/model/MockRace.java b/racevisionGame/src/main/java/mock/model/MockRace.java index 357d34ce..9bcece2c 100644 --- a/racevisionGame/src/main/java/mock/model/MockRace.java +++ b/racevisionGame/src/main/java/mock/model/MockRace.java @@ -43,7 +43,7 @@ public class MockRace extends RaceState { /** * Registry for all collider object in this race */ - protected ColliderRegistry colliderRegistry; + private ColliderRegistry colliderRegistry; /** @@ -58,6 +58,12 @@ public class MockRace extends RaceState { private WindGenerator windGenerator; + /** + * The polars file to use for each boat. + */ + private Polars polars; + + /** * Constructs a race object with a given RaceDataSource, BoatDataSource, and RegattaDataSource and sends events to the given mockOutput. @@ -74,9 +80,10 @@ public class MockRace extends RaceState { this.setRaceDataSource(raceDataSource); this.setRegattaDataSource(regattaDataSource); + this.polars = polars; this.scaleFactor = timeScale; - this.boats = this.generateMockBoats(boatDataSource.getBoats(), raceDataSource.getParticipants(), polars); + this.boats = new ArrayList<>(); this.shrinkBoundary = GPSCoordinate.getShrinkBoundary(this.getBoundary()); @@ -100,31 +107,35 @@ public class MockRace extends RaceState { /** - * Generates a list of MockBoats given a list of Boats, and a list of participating boats. - * @param boats The map of Boats describing boats that are potentially in the race. Maps boat sourceID to boat. - * @param sourceIDs The list of boat sourceIDs describing which specific boats are actually participating. - * @param polars The polars table to be used for boat simulation. - * @return A list of MockBoats that are participating in the race. + * Generates a MockBoat from the BoatDataSource, given a source ID. Also adds it to the participant list. + * @param sourceID The source ID to assign the boat. + * @return A MockBoat that is now participating in the race. */ - private List generateMockBoats(Map boats, List sourceIDs, Polars polars) { - - List mockBoats = new ArrayList<>(sourceIDs.size()); + public void generateMockBoat(Integer sourceID) { - //For each sourceID participating... - for (int sourceID : sourceIDs) { + //Get the boat associated with the sourceID. + Boat boat = getBoatDataSource().getBoats().get(sourceID); - //Get the boat associated with the sourceID. - Boat boat = boats.get(sourceID); + //Construct a MockBoat using the Boat and Polars. + MockBoat mockBoat = new MockBoat(boat, polars); + mockBoat.setCurrentLeg(this.getLegs().get(0)); - //Construct a MockBoat using the Boat and Polars. - MockBoat mockBoat = new MockBoat(boat, polars); + //Update participant list. + getRaceDataSource().getParticipants().add(sourceID); - mockBoats.add(mockBoat); + this.boats.add(mockBoat); - } - - return mockBoats; + getRaceDataSource().incrementSequenceNumber(); + } + /** + * Removes a MockBoat from the race, by sourceID. Also removes it from the participant list. + * @param sourceID Source ID of boat to remove. + */ + public void removeMockBoat(Integer sourceID) { + this.boats.removeIf(mockBoat -> mockBoat.getSourceID() == sourceID); + getRaceDataSource().getParticipants().remove(sourceID); + getRaceDataSource().incrementSequenceNumber(); } diff --git a/racevisionGame/src/main/java/mock/model/RaceLogic.java b/racevisionGame/src/main/java/mock/model/RaceLogic.java index 5b35d449..a1bddd9a 100644 --- a/racevisionGame/src/main/java/mock/model/RaceLogic.java +++ b/racevisionGame/src/main/java/mock/model/RaceLogic.java @@ -48,6 +48,9 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { */ @Override public void run() { + + prestartCountdown(); + race.initialiseBoats(); countdown(); @@ -60,6 +63,35 @@ public class RaceLogic implements RunnableWithFramePeriod, Observer { } + /** + * The countdown timer until the prestart period is finished. This timer will stop 3 minutes before the race starts, and players can no longer start participating. + */ + private void prestartCountdown() { + + long previousFrameTime = System.currentTimeMillis(); + + while (((race.getRaceStatusEnum() == RaceStatusEnum.PRESTART) + || (race.getRaceStatusEnum() == RaceStatusEnum.NOT_ACTIVE)) && loopBool) { + + long currentTime = System.currentTimeMillis(); + + //Update race time. + race.updateRaceTime(currentTime); + + //Update the race status based on the current time. + race.updateRaceStatusEnum(); + + //Provide boat's with an estimated time at next mark until the race starts. + race.setBoatsTimeNextMark(race.getRaceClock().getCurrentTime()); + + //Parse the race snapshot. + server.parseSnapshot(); + + waitForFramePeriod(previousFrameTime, currentTime, 50); + previousFrameTime = currentTime; + } + } + /** * Countdown timer until race starts. */ diff --git a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java index 3b62a8a7..b609e5a5 100644 --- a/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java +++ b/racevisionGame/src/main/java/mock/model/SourceIdAllocator.java @@ -2,6 +2,7 @@ package mock.model; import mock.exceptions.SourceIDAllocationException; +import network.Messages.Enums.RaceStatusEnum; import java.util.ArrayList; import java.util.List; @@ -13,24 +14,18 @@ public class SourceIdAllocator { /** - * This list contains all unallocated source IDs. + * The race we are allocating for. */ - List unallocatedIDs = new ArrayList<>(); + private MockRace mockRace; - /** - * This list contains all allocated source IDs. - */ - List allocatedIDs = new ArrayList<>(); - /** - * Creates a source ID allocator, using the given list of unallocated source IDs. - * @param unallocatedIDs List of unallocated source IDs. + * Creates a SourceIdAllocator for a given race. + * @param mockRace Race to allocate source IDs for. */ - public SourceIdAllocator(List unallocatedIDs) { - //We need to copy the list. - this.unallocatedIDs.addAll(unallocatedIDs); + public SourceIdAllocator(MockRace mockRace) { + this.mockRace = mockRace; } @@ -41,11 +36,23 @@ public class SourceIdAllocator { */ public synchronized int allocateSourceID() throws SourceIDAllocationException { + if (mockRace.getRaceStatusEnum() != RaceStatusEnum.PRESTART) { + throw new SourceIDAllocationException("Could not allocate a source ID. Can only allocate during pre-start period. It is currently: " + mockRace.getRaceStatusEnum()); + } + + List allocatedIDs = mockRace.getRaceDataSource().getParticipants(); + List allIDs = new ArrayList<>(mockRace.getBoatDataSource().getBoats().keySet()); + + //Get list of unallocated ids. + List unallocatedIDs = new ArrayList<>(allIDs); + unallocatedIDs.removeAll(allocatedIDs); + + if (!unallocatedIDs.isEmpty()) { int sourceID = unallocatedIDs.remove(0); - allocatedIDs.add(sourceID); + mockRace.generateMockBoat(sourceID); return sourceID; @@ -61,10 +68,6 @@ public class SourceIdAllocator { * @param sourceID Source ID to return. */ public void returnSourceID(Integer sourceID) { - - //We remove an Integer, not an int, so that we remove by value not by index. - allocatedIDs.remove(sourceID); - - unallocatedIDs.add(sourceID); + mockRace.removeMockBoat(sourceID); } } diff --git a/racevisionGame/src/main/java/shared/model/RaceState.java b/racevisionGame/src/main/java/shared/model/RaceState.java index 19a1a52c..48361da2 100644 --- a/racevisionGame/src/main/java/shared/model/RaceState.java +++ b/racevisionGame/src/main/java/shared/model/RaceState.java @@ -188,7 +188,20 @@ public abstract class RaceState { * @return List of mark boats. */ public List getMarks() { - return new ArrayList<>(boatDataSource.getMarkerBoats().values()); + //BoatDataSource contains a collection of Marks, and RaceDataSource contains a collection of Compound marks (which contain marks). RaceDataSource is the "definitive" source of mark data. + List marks = new ArrayList<>(getCompoundMarks().size() * 2); + + for (CompoundMark compoundMark : getCompoundMarks()) { + if (compoundMark.getMark1() != null) { + marks.add(compoundMark.getMark1()); + } + + if (compoundMark.getMark2() != null) { + marks.add(compoundMark.getMark2()); + } + } + + return marks; } /**