package mock.model; import javafx.animation.AnimationTimer; import mock.model.collider.Collision; import mock.model.commandFactory.Command; import mock.model.commandFactory.CompositeCommand; import mock.model.commandFactory.CommandFactory; import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.RaceStatusEnum; import network.Messages.LatestMessages; import shared.model.RunnableWithFramePeriod; import java.util.Observable; import java.util.Observer; public class RaceLogic implements RunnableWithFramePeriod, Observer { /** * State of current race modified by this object */ private MockRace race; /** * High-level interface to AC35 protocol server */ private RaceServer server; private CompositeCommand commands; private boolean loopBool = true; /** * Initialises race loop with state and server message queue * @param race state of race to modify * @param messages to send to server * @param compositeCommand Commands from clients to execute. */ public RaceLogic(MockRace race, LatestMessages messages, CompositeCommand compositeCommand) { this.race = race; this.server = new RaceServer(race, messages); this.commands = compositeCommand; race.getColliderRegistry().addObserver(this); } /** * Initialise boats and start countdown timer */ @Override public void run() { prestartCountdown(); race.initialiseBoats(); countdown(); raceLoop(); } public void boolFalse(){ loopBool = false; } /** * 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) || (race.getRaceStatusEnum() == RaceStatusEnum.WARNING)) && 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. */ private void countdown() { long previousFrameTime = System.currentTimeMillis(); while (race.getRaceStatusEnum() != RaceStatusEnum.STARTED && 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(); // Change wind direction race.changeWindDirection(); if (race.getRaceStatusEnum() == RaceStatusEnum.STARTED) { race.setBoatsStatusToRacing(); } waitForFramePeriod(previousFrameTime, currentTime, 50); previousFrameTime = currentTime; } } /** * Timer that runs for the duration of the race, until all boats finish. */ private void raceLoop() { long previousFrameTime = System.currentTimeMillis(); while (race.getRaceStatusEnum() != RaceStatusEnum.FINISHED && loopBool) { //Get the current time. long currentTime = System.currentTimeMillis(); //Execute commands from clients. commands.execute(); //Update race time. race.updateRaceTime(currentTime); //As long as there is at least one boat racing, we still simulate the race. if (race.getNumberOfActiveBoats() != 0) { //Get the time period of this frame. long framePeriod = currentTime - previousFrameTime; //For each boat, we update its position, and generate a BoatLocationMessage. for (MockBoat boat : race.getBoats()) { //If it is still racing, update its position. if (boat.getStatus() == BoatStatusEnum.RACING) { race.updatePosition(boat, framePeriod, race.getRaceClock().getDurationMilli()); race.getColliderRegistry().rayCast(boat); } } } else { //Otherwise, the race is over! raceFinished.start(); race.setRaceStatusEnum(RaceStatusEnum.FINISHED); } if (race.getNumberOfActiveBoats() != 0) { // Change wind direction race.changeWindDirection(); //Parse the race snapshot. server.parseSnapshot(); //Update the last frame time. previousFrameTime = currentTime; } waitForFramePeriod(previousFrameTime, currentTime, 50); previousFrameTime = currentTime; } } /** * Broadcast that the race has finished. */ protected AnimationTimer raceFinished = new AnimationTimer(){ int iters = 0; @Override public void handle(long now) { server.parseSnapshot(); if (iters > 500) { stop(); } iters++; } }; /** * Returns the race state that this RaceLogic is simulating. * @return Race state this RaceLogic is simulating. */ public MockRace getRace() { return race; } @Override public void update(Observable o, Object arg) { Collision e = (Collision)arg; // if(e.getBearing().degrees() == 0) System.out.println("Ahead"); // else if(e.getBearing().degrees() < 90) System.out.println("Starboard"); // else if(e.getBearing().degrees() > 270) System.out.println("Port"); // else System.out.println("Behind"); } }