|
|
|
|
@ -8,13 +8,12 @@ import org.geotools.referencing.GeodeticCalculator;
|
|
|
|
|
import seng302.DataInput.RaceDataSource;
|
|
|
|
|
|
|
|
|
|
import SharedModel.*;
|
|
|
|
|
import seng302.Networking.MessageEncoders.RaceVisionByteEncoder;
|
|
|
|
|
import seng302.Networking.MockOutput;
|
|
|
|
|
import seng302.Networking.Utils.BoatLocationMessage;
|
|
|
|
|
import seng302.Networking.Utils.BoatStatusMessage;
|
|
|
|
|
import seng302.Networking.Utils.Enums.BoatStatus;
|
|
|
|
|
import seng302.Networking.Utils.RaceStatus;
|
|
|
|
|
|
|
|
|
|
import java.awt.geom.Point2D;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Random;
|
|
|
|
|
@ -30,10 +29,10 @@ public class Race implements Runnable {
|
|
|
|
|
protected List<Leg> legs;
|
|
|
|
|
protected int boatsFinished = 0;
|
|
|
|
|
protected long totalTimeElapsed;
|
|
|
|
|
protected int heartbeat = 0;
|
|
|
|
|
protected int scaleFactor;
|
|
|
|
|
protected int PRERACE_TIME = 120000; //time in milliseconds to pause during pre-race
|
|
|
|
|
protected int PRERACE_TIME = 12; //time in milliseconds to pause during pre-race
|
|
|
|
|
private int lastFPS = 20;
|
|
|
|
|
private int raceId;
|
|
|
|
|
private int dnfChance = 0; //percentage chance a boat fails at each checkpoint
|
|
|
|
|
private MockOutput mockOutput;
|
|
|
|
|
|
|
|
|
|
@ -64,6 +63,10 @@ public class Race implements Runnable {
|
|
|
|
|
this(raceData.getBoats(), raceData.getLegs(), scaleFactor, mockOutput);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setRaceId(int raceId) {
|
|
|
|
|
this.raceId = raceId;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the boats next GPS position based on its distance travelled and heading
|
|
|
|
|
*
|
|
|
|
|
@ -131,25 +134,6 @@ public class Race implements Runnable {
|
|
|
|
|
timer.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Takes total time elapsed and format to hour:minute:second
|
|
|
|
|
*
|
|
|
|
|
* @return Formatted time as string
|
|
|
|
|
*/
|
|
|
|
|
protected String calcTimer() {
|
|
|
|
|
long minutes;
|
|
|
|
|
long currentTimeInSeconds;
|
|
|
|
|
long remainingSeconds;
|
|
|
|
|
long hours;
|
|
|
|
|
|
|
|
|
|
currentTimeInSeconds = (totalTimeElapsed * scaleFactor) / 1000;
|
|
|
|
|
minutes = currentTimeInSeconds / 60;
|
|
|
|
|
remainingSeconds = currentTimeInSeconds % 60;
|
|
|
|
|
hours = minutes / 60;
|
|
|
|
|
minutes = minutes % 60;
|
|
|
|
|
return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Starts the Race Simulation, playing the race start to finish with the timescale.
|
|
|
|
|
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
|
|
|
|
|
@ -173,6 +157,7 @@ public class Race implements Runnable {
|
|
|
|
|
long currentTime = System.currentTimeMillis();
|
|
|
|
|
//Update the total elapsed time.
|
|
|
|
|
totalTimeElapsed = currentTime - timeRaceStarted;
|
|
|
|
|
ArrayList<BoatStatusMessage> boatStatusMessages = new ArrayList<BoatStatusMessage>();
|
|
|
|
|
|
|
|
|
|
//For each boat, we update it's position, and generate a BoatLocationMessage.
|
|
|
|
|
for (BoatInRace boat : startingBoats) {
|
|
|
|
|
@ -180,47 +165,15 @@ public class Race implements Runnable {
|
|
|
|
|
//Update position.
|
|
|
|
|
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
|
|
|
|
|
checkPosition(boat, totalTimeElapsed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Generate a boat location message for the updated boat.
|
|
|
|
|
BoatLocationMessage boatLocationMessage = new BoatLocationMessage();
|
|
|
|
|
boatLocationMessage.setTime(currentTime);
|
|
|
|
|
boatLocationMessage.setSourceID(boat.getSourceID());
|
|
|
|
|
boatLocationMessage.setSequenceNumber(boat.getNextSequenceNumber());
|
|
|
|
|
boatLocationMessage.setDeviceType(BoatLocationMessage.RacingYacht);
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setLatitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLatitude()));
|
|
|
|
|
boatLocationMessage.setLongitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLongitude()));
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setAltitude(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setHeading(BoatLocationMessage.convertHeadingDoubleToInt(boat.getHeading()));
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setPitch((short) 0);//Junk value.
|
|
|
|
|
boatLocationMessage.setRoll((short) 0);//Junk value.
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setBoatSpeed(BoatLocationMessage.convertBoatSpeedDoubleToInt(boat.getVelocity()));
|
|
|
|
|
boatLocationMessage.setBoatCOG(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setBoatSOG(0);//Junk value.
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setApparentWindSpeed(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setApparentWindAngle((short) 0);//Junk value.
|
|
|
|
|
boatLocationMessage.setTrueWindSpeed(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setTrueWindDirection(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setTrueWindAngle((short) 0);//Junk value.
|
|
|
|
|
|
|
|
|
|
boatLocationMessage.setCurrentDrift(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setCurrentSet(0);//Junk value.
|
|
|
|
|
boatLocationMessage.setRudderAngle((short) 0);//Junk value.
|
|
|
|
|
|
|
|
|
|
//We have finished creating the message.
|
|
|
|
|
|
|
|
|
|
mockOutput.parseBoatLocation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mockOutput.parseBoatLocation(boat);
|
|
|
|
|
boatStatusMessages.add(new BoatStatusMessage(boat.getSourceID(),
|
|
|
|
|
boat.getCurrentLeg().getLegNumber() >= 0 ? BoatStatus.RACING : BoatStatus.DNF, boat.getCurrentLeg().getLegNumber()));
|
|
|
|
|
} else {
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RaceStatus raceStatus = new RaceStatus(totalTimeElapsed, raceId, 3, 2, boatStatusMessages);
|
|
|
|
|
mockOutput.parseRaceStatus();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}.start();
|
|
|
|
|
|