Merge branch 'master' into story_61

Also got client-server handshake working. Multiple clients can connect and control their own boat.
The client's boat has a larger black triangle drawn around it. Probably needs tidying up.
Added isClientBoat boolean to VisualiserBoat.

WindGenerator is now an interface, implemented by ConstantWindGenerator (useful for testing) and RandomWindGenerator. Added ConstantWindGeneratorTest.
RandomWindGenerator was formerly WindGenerator.
The WindGenerator is passed in to MockRace.

CommandFactory throws a CommandConstructionException if it cannot create a command.

MessageSerialiser and MessageDeserialiser correctly terminate on error.

Readded VisualiserInput's switch statement in the main loop, pending a refactor.

Removed the sleep statement from LobbyController - it was blocking javaFX thread.

Lobby.fxml: moved buttons and text input into grid panes, so they don't break when you resize screen.

Added some test object creation functions in several test classes (MockRaceTest.createMockRace(), BoatXMLReaderTest.createBoatDataSource(), etc...).

#story[1095]
This commit is contained in:
fjc40
2017-08-10 23:49:21 +12:00
45 changed files with 1320 additions and 556 deletions
@@ -1,8 +1,10 @@
package mock.model.commandFactory;
import mock.exceptions.CommandConstructionException;
import mock.model.MockBoat;
import mock.model.MockRace;
import network.Messages.Enums.BoatActionEnum;
import network.Messages.BoatAction;
import shared.exceptions.BoatNotFoundException;
/**
* Factory class for Command objects
@@ -11,15 +13,28 @@ public class CommandFactory {
/**
* Generates a command on a race and boat corresponding to the protocol action number.
* @param race to receive command
* @param boat to receive command in race
* @param action number to select command
* @return
* @return The command to execute the given action.
* @throws CommandConstructionException Thrown if the command cannot be constructed (e.g., unknown action type).
*/
public static Command createCommand(MockRace race, MockBoat boat, BoatActionEnum action) {
switch(action) {
public static Command createCommand(MockRace race, BoatAction action) throws CommandConstructionException {
MockBoat boat = null;
try {
boat = race.getBoat(action.getSourceID());
} catch (BoatNotFoundException e) {
throw new CommandConstructionException("Could not create command for BoatAction: " + action + ". Boat with sourceID: " + action.getSourceID() + " not found.", e);
}
switch(action.getBoatAction()) {
case AUTO_PILOT: return new VMGCommand(race, boat);
case TACK_GYBE: return new TackGybeCommand(race, boat);
default: return null; // TODO - please please have discussion over what to default to
case UPWIND: return new WindCommand(race, boat, true);
case DOWNWIND: return new WindCommand(race, boat, false);
default: throw new CommandConstructionException("Could not create command for BoatAction: " + action + ". Unknown BoatAction.");
}
}
}
@@ -1,25 +1,24 @@
package mock.model.commandFactory;
import mock.model.MockRace;
import java.util.Stack;
import java.util.ArrayDeque;
import java.util.Queue;
/**
* Wraps multiple commands into a composite to execute queued commands during a frame.
*/
public class CompositeCommand implements Command {
private Stack<Command> commands;
private Queue<Command> commands;
public CompositeCommand() {
this.commands = new Stack<>();
this.commands = new ArrayDeque<>();
}
public void addCommand(Command command) {
commands.push(command);
commands.add(command);
}
@Override
public void execute(MockRace race) {
while(!commands.isEmpty()) commands.pop().execute(race);
public void execute() {
while(!commands.isEmpty()) commands.remove().execute();
}
}
@@ -18,6 +18,9 @@ public class TackGybeCommand implements Command {
//The refactoring of MockRace will require changes to be made
@Override
public void execute() {
boat.setAutoVMG(false);
/*VMG newVMG = boat.getPolars().calculateVMG(
race.getWindDirection(),
race.getWindSpeed(),
@@ -18,6 +18,7 @@ public class VMGCommand implements Command {
//The refactoring of MockRace will require changes to be made
@Override
public void execute() {
boat.setAutoVMG(true);
/*VMG newVMG = boat.getPolars().calculateVMG(
race.getWindDirection(),
race.getWindSpeed(),
@@ -0,0 +1,37 @@
package mock.model.commandFactory;
import mock.model.MockBoat;
import mock.model.MockRace;
import shared.model.Bearing;
/**
* Created by connortaylorbrown on 4/08/17.
*/
public class WindCommand implements Command {
private MockRace race;
private MockBoat boat;
private int direction;
public WindCommand(MockRace race, MockBoat boat, boolean upwind) {
this.race = race;
this.boat = boat;
this.direction = upwind? -1 : 1;
}
@Override
public void execute() {
boat.setAutoVMG(false);
double wind = race.getWindDirection().degrees();
double heading = boat.getBearing().degrees();
double offset = 3.0;
offset *= direction;
double headWindDelta = wind - heading;
if ((headWindDelta < 0) || (headWindDelta > 180)) offset *= -1;
boat.setBearing(Bearing.fromDegrees(heading + offset));
}
}