Game state now updates based on boat position. Arrows drawn as boat travels course. Currently do not point in correct direction, also the sparkline does not work.

#bug #refactor #implement #story[1118]
This commit is contained in:
Calum
2017-08-16 03:51:48 +12:00
parent 7329f7dc65
commit ac47e9d88a
51 changed files with 358 additions and 271 deletions
@@ -8,13 +8,13 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.server.messages.BoatStatus; import seng302.gameServer.messages.BoatStatus;
import seng302.gameServer.server.messages.MarkRoundingMessage; import seng302.gameServer.messages.MarkRoundingMessage;
import seng302.gameServer.server.messages.MarkType; import seng302.gameServer.messages.MarkType;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.server.messages.RoundingBoatStatus; import seng302.gameServer.messages.RoundingBoatStatus;
import seng302.gameServer.server.messages.YachtEventCodeMessage; import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.PolarTable; import seng302.model.PolarTable;
@@ -283,7 +283,7 @@ public class GameState implements Runnable {
Double velocity = yacht.getCurrentVelocity(); Double velocity = yacht.getCurrentVelocity();
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots); Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * 3;
// TODO: 15/08/17 remove magic numbers from these equations. // TODO: 15/08/17 remove magic numbers from these equations.
if (yacht.getSailIn()) { if (yacht.getSailIn()) {
if (velocity < maxBoatSpeed - 500) { if (velocity < maxBoatSpeed - 500) {
@@ -556,7 +556,7 @@ public class GameState implements Runnable {
// TODO: 13/8/17 figure out the rounding side, rounded mark source ID and boat status. // TODO: 13/8/17 figure out the rounding side, rounded mark source ID and boat status.
Message markRoundingMessage = new MarkRoundingMessage(0, 0, Message markRoundingMessage = new MarkRoundingMessage(0, 0,
sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType, sourceID, RoundingBoatStatus.RACING, roundingMark.getRoundingSide(), markType,
roundingMark.getSourceID()); currentMarkSeqID + 1);
notifyMessageListeners(markRoundingMessage); notifyMessageListeners(markRoundingMessage);
} }
@@ -5,8 +5,8 @@ import java.util.Stack;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import seng302.model.Player; import seng302.model.Player;
import seng302.gameServer.server.messages.Heartbeat; import seng302.gameServer.messages.Heartbeat;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
/** /**
* Send Heartbeat messages to connected player at a specified interval * Send Heartbeat messages to connected player at a specified interval
@@ -6,7 +6,7 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.PolarTable; import seng302.model.PolarTable;
@@ -2,10 +2,10 @@ package seng302.gameServer;
import java.util.Arrays; import java.util.Arrays;
import seng302.gameServer.server.messages.ClientType; import seng302.gameServer.messages.ClientType;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
public class ServerPacketParser { public class ServerPacketParser {
@@ -19,25 +19,25 @@ import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.server.messages.YachtEventCodeMessage; import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta; import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.server.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.server.messages.BoatSubMessage; import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.server.messages.ClientType; import seng302.gameServer.messages.ClientType;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.server.messages.RaceStatus; import seng302.gameServer.messages.RaceStatus;
import seng302.gameServer.server.messages.RaceStatusMessage; import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.server.messages.RaceType; import seng302.gameServer.messages.RaceType;
import seng302.gameServer.server.messages.RegistrationResponseMessage; import seng302.gameServer.messages.RegistrationResponseMessage;
import seng302.gameServer.server.messages.RegistrationResponseStatus; import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.gameServer.server.messages.XMLMessage; import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.server.messages.XMLMessageSubType; import seng302.gameServer.messages.XMLMessageSubType;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
/** /**
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Created by kre39 on 12/07/17. * Created by kre39 on 12/07/17.
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class BoatLocationMessage extends Message { public class BoatLocationMessage extends Message {
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* The current status of a boat * The current status of a boat
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Created by kre39 on 20/07/17. * Created by kre39 on 20/07/17.
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public enum ClientType { public enum ClientType {
SPECTATOR(0x00), SPECTATOR(0x00),
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public enum DeviceType { public enum DeviceType {
UNKNOWN(0), UNKNOWN(0),
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class Heartbeat extends Message { public class Heartbeat extends Message {
private final int MESSAGE_SIZE = 4; private final int MESSAGE_SIZE = 4;
@@ -1,6 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import seng302.gameServer.GameState;
public class MarkRoundingMessage extends Message{ public class MarkRoundingMessage extends Message{
private final long MESSAGE_VERSION_NUMBER = 1; private final long MESSAGE_VERSION_NUMBER = 1;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Types of marks boats can round * Types of marks boats can round
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Enum containing the types of messages * Enum containing the types of messages
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* The types of race start status messages * The types of race start status messages
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class RaceStartStatusMessage extends Message { public class RaceStartStatusMessage extends Message {
private final int MESSAGE_SIZE = 20; private final int MESSAGE_SIZE = 20;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* The current status of the race * The current status of the race
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
import java.util.List; import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Enum containing the types of races * Enum containing the types of races
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class RegistrationRequestMessage extends Message { public class RegistrationRequestMessage extends Message {
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class RegistrationResponseMessage extends Message{ public class RegistrationResponseMessage extends Message{
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public enum RegistrationResponseStatus { public enum RegistrationResponseStatus {
SUCCESS_SPECTATING(0x00), SUCCESS_SPECTATING(0x00),
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* The status of a boat rounding a mark * The status of a boat rounding a mark
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* The side the boat rounded the mark * The side the boat rounded the mark
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
public class XMLMessage extends Message{ public class XMLMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE; private final MessageType MESSAGE_TYPE = MessageType.XML_MESSAGE;
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Enum containing the types of XML messages * Enum containing the types of XML messages
@@ -1,4 +1,4 @@
package seng302.gameServer.server.messages; package seng302.gameServer.messages;
/** /**
* Created by zyt10 on 10/08/17. * Created by zyt10 on 10/08/17.
+35 -13
View File
@@ -8,6 +8,8 @@ import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongProperty;
import javafx.beans.property.ReadOnlyLongWrapper; import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -28,6 +30,11 @@ public class ClientYacht extends Observable {
Boolean sailsIn, double velocity); Boolean sailsIn, double velocity);
} }
@FunctionalInterface
public interface MarkRoundingListener {
void notifyRounding(ClientYacht yacht, CompoundMark markPassed, int legNumber);
}
private Logger logger = LoggerFactory.getLogger(ClientYacht.class); private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
@@ -52,11 +59,12 @@ public class ClientYacht extends Observable {
//CLIENT SIDE //CLIENT SIDE
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
private CompoundMark lastMarkRounded; private CompoundMark lastMarkRounded;
private Integer positionInt = 0;
private Color colour; private Color colour;
public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName, public ClientYacht(String boatType, Integer sourceId, String hullID, String shortName,
@@ -145,12 +153,16 @@ public class ClientYacht extends Observable {
this.estimateTimeAtFinish = estimateTimeAtFinish; this.estimateTimeAtFinish = estimateTimeAtFinish;
} }
public Integer getPositionInteger() { public Integer getPlacing() {
return positionInt; return placingProperty.get();
} }
public void setPositionInteger(Integer position) { public void setPlacing(Integer position) {
this.positionInt = position; placingProperty.set(position);
}
public ReadOnlyIntegerProperty placingProperty() {
return placingProperty.getReadOnlyProperty();
} }
public void updateVelocityProperty(double velocity) { public void updateVelocityProperty(double velocity) {
@@ -239,14 +251,6 @@ public class ClientYacht extends Observable {
this.colour = colour; this.colour = colour;
} }
// public Double getCurrentVelocity() {
// return currentVelocity;
// }
//
// public void setCurrentVelocity(Double currentVelocity) {
// this.currentVelocity = currentVelocity;
// }
public void updateLocation(double lat, double lng, double heading, double velocity) { public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng); setLocation(lat, lng);
@@ -262,7 +266,25 @@ public class ClientYacht extends Observable {
locationListeners.add(listener); locationListeners.add(listener);
} }
public void addMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.add(listener);
}
public void removeMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.remove(listener);
}
public boolean getSailIn () { public boolean getSailIn () {
return sailIn; return sailIn;
} }
public void roundMark(CompoundMark mark, long markRoundTime, long timeSinceLastMark) {
this.markRoundTime = markRoundTime;
timeSinceLastMarkProperty.set(timeSinceLastMark);
lastMarkRounded = mark;
legNumber += 1;
for (MarkRoundingListener listener : markRoundingListeners) {
listener.notifyRounding(this, lastMarkRounded, legNumber);
}
}
} }
+30 -6
View File
@@ -2,7 +2,11 @@ package seng302.model;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import seng302.model.stream.parser.RaceStartData; import seng302.model.stream.parser.RaceStartData;
import seng302.model.stream.parser.RaceStatusData; import seng302.model.stream.parser.RaceStatusData;
@@ -12,22 +16,27 @@ import seng302.model.stream.parser.RaceStatusData;
*/ */
public class RaceState { public class RaceState {
@FunctionalInterface
public interface CollisionListener {
void notifyCollision(GeoPoint location);
}
// private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); // private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); private final DateFormat DATE_TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
private double windSpeed; private double windSpeed;
private double windDirection; private ReadOnlyDoubleWrapper windDirection = new ReadOnlyDoubleWrapper();
private long raceTime; private long raceTime;
private long expectedStartTime; private long expectedStartTime;
private boolean isRaceStarted = false; private boolean isRaceStarted = false;
// long timeTillStart; private List<ClientYacht> collisions = new ArrayList<>();
private List<CollisionListener> collisionListeners = new ArrayList<>();
public RaceState() { public RaceState() {
} }
public void updateState (RaceStatusData data) { public void updateState (RaceStatusData data) {
this.windSpeed = data.getWindSpeed(); this.windSpeed = data.getWindSpeed();
this.windDirection = data.getWindDirection(); this.windDirection.set(data.getWindDirection());
this.raceTime = data.getCurrentTime(); this.raceTime = data.getCurrentTime();
this.expectedStartTime = data.getExpectedStartTime(); this.expectedStartTime = data.getExpectedStartTime();
this.isRaceStarted = data.isRaceStarted(); this.isRaceStarted = data.isRaceStarted();
@@ -54,8 +63,8 @@ public class RaceState {
return windSpeed; return windSpeed;
} }
public double getWindDirection() { public ReadOnlyDoubleProperty windDirectionProperty() {
return windDirection; return windDirection.getReadOnlyProperty();
} }
public long getRaceTime() { public long getRaceTime() {
@@ -69,4 +78,19 @@ public class RaceState {
public boolean isRaceStarted () { public boolean isRaceStarted () {
return isRaceStarted; return isRaceStarted;
} }
public void storeCollision(ClientYacht yacht) {
collisions.add(yacht);
for (CollisionListener collisionListener : collisionListeners) {
collisionListener.notifyCollision(yacht.getLocation());
}
}
public void addCollisionListener(CollisionListener collisionListener) {
collisionListeners.add(collisionListener);
}
public void removeCollisionListener(CollisionListener collisionListener) {
collisionListeners.remove(collisionListener);
}
} }
+1 -1
View File
@@ -6,7 +6,7 @@ import java.util.Observer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.gameServer.server.messages.BoatStatus; import seng302.gameServer.messages.BoatStatus;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
@@ -2,7 +2,7 @@ package seng302.model.mark;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.server.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
+1 -1
View File
@@ -2,7 +2,7 @@ package seng302.model.mark;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.server.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
/** /**
@@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import seng302.gameServer.server.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
@@ -119,12 +119,12 @@ public class StreamParser {
// placing += 1; // placing += 1;
// } // }
// } // }
// updatingBoat.setPosition(placing.toString()); // updatingBoat.setPlacing(placing.toString());
// updatingBoat.setLegNumber(leg); // updatingBoat.setLegNumber(leg);
// boatsPos.putIfAbsent(placing, updatingBoat); // boatsPos.putIfAbsent(placing, updatingBoat);
// boatsPos.replace(placing, updatingBoat); // boatsPos.replace(placing, updatingBoat);
// } else if(updatingBoat.getLegNumber() == null){ // } else if(updatingBoat.getLegNumber() == null){
// updatingBoat.setPosition("1"); // updatingBoat.setPlacing("1");
// updatingBoat.setLegNumber(leg); // updatingBoat.setLegNumber(leg);
// } // }
// } // }
@@ -9,7 +9,7 @@ import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import seng302.model.stream.xml.generator.Race; import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta; import seng302.model.stream.xml.generator.Regatta;
import seng302.gameServer.server.messages.XMLMessageSubType; import seng302.gameServer.messages.XMLMessageSubType;
/** /**
* An XML generator to generate the Race, Boat, and Regatta XML dynamically * An XML generator to generate the Race, Boat, and Regatta XML dynamically
@@ -21,12 +21,12 @@ import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.server.messages.BoatActionMessage; import seng302.gameServer.messages.BoatActionMessage;
import seng302.gameServer.server.messages.ClientType; import seng302.gameServer.messages.ClientType;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.server.messages.RegistrationRequestMessage; import seng302.gameServer.messages.RegistrationRequestMessage;
import seng302.gameServer.server.messages.RegistrationResponseStatus; import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
@@ -13,7 +13,7 @@ import javafx.scene.Node;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
@@ -141,17 +141,7 @@ public class GameClient {
} }
private void loadRaceView() { private void loadRaceView() {
FXMLLoader fxmlLoader = new FXMLLoader( FXMLLoader fxmlLoader = loadFXMLToHolder("/views/RaceView.fxml");
RaceViewController.class.getResource("/views/RaceView.fxml"));
try {
final Node node = fxmlLoader.load();
Platform.runLater(() -> {
holderPane.getChildren().clear();
holderPane.getChildren().add(node);
});
} catch (IOException e) {
e.printStackTrace();
}
holderPane.getScene().setOnKeyPressed(this::keyPressed); holderPane.getScene().setOnKeyPressed(this::keyPressed);
holderPane.getScene().setOnKeyReleased(this::keyReleased); holderPane.getScene().setOnKeyReleased(this::keyReleased);
raceView = fxmlLoader.getController(); raceView = fxmlLoader.getController();
@@ -160,17 +150,23 @@ public class GameClient {
} }
private void loadFinishScreenView() { private void loadFinishScreenView() {
loadFXMLToHolder("/views/FinishScreenView.fxml");
}
private FXMLLoader loadFXMLToHolder(String fxmlLocation) {
FXMLLoader fxmlLoader = new FXMLLoader( FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/views/FinishScreenView.fxml")); getClass().getResource(fxmlLocation)
);
try { try {
final Node finishScreenFX = fxmlLoader.load(); final Node fxmlLoaderFX = fxmlLoader.load();
Platform.runLater(() -> { Platform.runLater(() -> {
holderPane.getChildren().clear(); holderPane.getChildren().clear();
holderPane.getChildren().add(finishScreenFX); holderPane.getChildren().add(fxmlLoaderFX);
}); });
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return fxmlLoader;
} }
private void parsePackets() { private void parsePackets() {
@@ -247,8 +243,8 @@ public class GameClient {
private void updatePosition(PositionUpdateData positionData) { private void updatePosition(PositionUpdateData positionData) {
if (positionData.getType() == DeviceType.YACHT_TYPE) { if (positionData.getType() == DeviceType.YACHT_TYPE) {
if (allXMLReceived() && allBoatsMap.containsKey(positionData.getDeviceId())) { if (allXMLReceived() && allBoatsMap.containsKey(positionData.getDeviceId())) {
ClientYacht clientYacht = allBoatsMap.get(positionData.getDeviceId()); ClientYacht yacht = allBoatsMap.get(positionData.getDeviceId());
clientYacht.updateLocation(positionData.getLat(), yacht.updateLocation(positionData.getLat(),
positionData.getLon(), positionData.getHeading(), positionData.getLon(), positionData.getHeading(),
positionData.getGroundSpeed()); positionData.getGroundSpeed());
} }
@@ -265,14 +261,26 @@ public class GameClient {
*/ */
private void updateMarkRounding(MarkRoundingData roundingData) { private void updateMarkRounding(MarkRoundingData roundingData) {
if (allXMLReceived()) { if (allXMLReceived()) {
ClientYacht clientYacht = allBoatsMap.get(roundingData.getBoatId()); ClientYacht yacht = allBoatsMap.get(roundingData.getBoatId());
clientYacht.setMarkRoundingTime(roundingData.getTimeStamp()); int placing = 1;
clientYacht.updateTimeSinceLastMarkProperty( int originalPlacing = yacht.getPlacing();
raceState.getRaceTime() - roundingData.getTimeStamp()); for (ClientYacht otherYacht : allBoatsMap.values()) {
clientYacht.setLastMarkRounded( if (otherYacht != yacht && yacht.getLegNumber() + 1 <= otherYacht.getLegNumber()) {
courseData.getCompoundMarks().get( placing++;
roundingData.getMarkId() }
) }
if (placing != originalPlacing) {
yacht.setPlacing(placing);
for (ClientYacht otherYacht : allBoatsMap.values()) {
if (otherYacht.getPlacing() < placing) {
otherYacht.setPlacing(otherYacht.getPlacing() + 1);
}
}
}
yacht.roundMark(
courseData.getCompoundMarks().get(roundingData.getMarkId()),
roundingData.getTimeStamp(),
raceState.getRaceTime() - roundingData.getTimeStamp()
); );
} }
} }
@@ -280,35 +288,33 @@ public class GameClient {
private void processRaceStatusUpdate(RaceStatusData data) { private void processRaceStatusUpdate(RaceStatusData data) {
if (allXMLReceived()) { if (allXMLReceived()) {
raceState.updateState(data); raceState.updateState(data);
if (raceView != null) {
raceView.getGameView().setWindDir(raceState.getWindDirection());
}
boolean raceFinished = true; boolean raceFinished = true;
for (ClientYacht yacht : allBoatsMap.values()) { for (ClientYacht yacht : allBoatsMap.values()) {
if (yacht.getBoatStatus() != 3) { if (yacht.getBoatStatus() != 3) {
raceFinished = false; raceFinished = false;
} }
} }
if (raceFinished == true) { if (raceFinished) {
loadFinishScreenView(); loadFinishScreenView();
} }
for (long[] boatData : data.getBoatData()) { for (long[] boatData : data.getBoatData()) {
ClientYacht clientYacht = allBoatsMap.get((int) boatData[0]); ClientYacht yacht = allBoatsMap.get((int) boatData[0]);
clientYacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]); yacht.setEstimateTimeTillNextMark(raceState.getRaceTime() - boatData[1]);
clientYacht.setEstimateTimeAtFinish(boatData[2]); yacht.setEstimateTimeAtFinish(boatData[2]);
int legNumber = (int) boatData[3]; int legNumber = (int) boatData[3];
clientYacht.setLegNumber(legNumber); // yacht.setLegNumber(legNumber);
clientYacht.setBoatStatus((int) boatData[4]); yacht.setBoatStatus((int) boatData[4]);
if (legNumber != clientYacht.getLegNumber()) { // if (legNumber != yacht.getLegNumber()) {
int placing = 1; // System.out.println("WHAT THE FUCK IT WORKS????");
for (ClientYacht otherClientYacht : allBoatsMap.values()) { // int placing = 1;
if (otherClientYacht.getSourceId() != boatData[0] && // for (ClientYacht otherClientYacht : allBoatsMap.values()) {
clientYacht.getLegNumber() <= otherClientYacht.getLegNumber()) // if (otherClientYacht.getSourceId() != boatData[0] &&
placing++; // yacht.getLegNumber() <= otherClientYacht.getLegNumber())
} // placing++;
clientYacht.setPositionInteger(placing); // }
} // yacht.setPlacing(placing);
// }
} }
} }
} }
@@ -347,7 +353,7 @@ public class GameClient {
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
case SHIFT: // sails in/sails out case SHIFT: // sails in/sails out
socketThread.sendBoatAction(BoatAction.SAILS_IN); socketThread.sendBoatAction(BoatAction.SAILS_IN);
raceView.getGameView().getPlayerYacht().toggleSail(); allBoatsMap.get(socketThread.getClientId()).toggleSail();
break; break;
case PAGE_UP: case PAGE_UP:
case PAGE_DOWN: case PAGE_DOWN:
@@ -365,7 +371,11 @@ public class GameClient {
private void showCollisionAlert(YachtEventData yachtEventData) { private void showCollisionAlert(YachtEventData yachtEventData) {
// 33 is the agreed code to show collision // 33 is the agreed code to show collision
if (yachtEventData.getEventId() == 33) { if (yachtEventData.getEventId() == 33) {
raceView.showCollision(yachtEventData.getSubjectId()); raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
} }
} }
} }
+77 -36
View File
@@ -7,7 +7,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import javafx.animation.AnimationTimer; import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.KeyValue; import javafx.animation.KeyValue;
@@ -25,8 +24,8 @@ import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle; import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import seng302.model.ClientYacht;
import javafx.util.Duration; import javafx.util.Duration;
import seng302.model.ClientYacht;
import seng302.model.Colors; import seng302.model.Colors;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Limit; import seng302.model.Limit;
@@ -34,7 +33,12 @@ import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.*; import seng302.visualiser.fxObjects.AnnotationBox;
import seng302.visualiser.fxObjects.BoatObject;
import seng302.visualiser.fxObjects.CourseBoundary;
import seng302.visualiser.fxObjects.Gate;
import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.Marker;
import seng302.visualiser.map.Boundary; import seng302.visualiser.map.Boundary;
import seng302.visualiser.map.CanvasMap; import seng302.visualiser.map.CanvasMap;
@@ -74,6 +78,7 @@ public class GameView extends Pane {
private Group boatObjectGroup = new Group(); private Group boatObjectGroup = new Group();
private Group trails = new Group(); private Group trails = new Group();
private Group markers = new Group(); private Group markers = new Group();
private List<CompoundMark> course = new ArrayList<>();
private ImageView mapImage = new ImageView(); private ImageView mapImage = new ImageView();
@@ -212,6 +217,20 @@ public class GameView extends Pane {
*/ */
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) { public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
markerObjects = new HashMap<>(); markerObjects = new HashMap<>();
for (Corner corner : sequence) { //Makes course out of all compound marks.
for (CompoundMark compoundMark : newCourse) {
if (corner.getCompoundMarkID() == compoundMark.getId()) {
course.add(compoundMark);
}
}
}
int j = 0;
for (CompoundMark cm : course) {
System.out.println(cm.getId() + " " + j++);
System.out.println(cm.toString());
}
final List<Gate> gates = new ArrayList<>(); final List<Gate> gates = new ArrayList<>();
Paint colour = Color.BLACK; Paint colour = Color.BLACK;
//Creates new markers //Creates new markers
@@ -344,23 +363,23 @@ public class GameView extends Pane {
/** /**
* Draws all the boats. * Draws all the boats.
* @param clientYachts The yachts to set in the race * @param yachts The yachts to set in the race
*/ */
public void setBoats(List<ClientYacht> clientYachts) { public void setBoats(List<ClientYacht> yachts) {
BoatObject newBoat; BoatObject newBoat;
final List<Group> wakes = new ArrayList<>(); final List<Group> wakes = new ArrayList<>();
for (ClientYacht clientYacht : clientYachts) { for (ClientYacht yacht : yachts) {
Paint colour = Colors.getColor(); Paint colour = Colors.getColor();
newBoat = new BoatObject(); newBoat = new BoatObject();
newBoat.setFill(colour); newBoat.setFill(colour);
boatObjects.put(clientYacht, newBoat); boatObjects.put(yacht, newBoat);
createAndBindAnnotationBox(clientYacht, colour); createAndBindAnnotationBox(yacht, colour);
// wakesGroup.getChildren().add(newBoat.getWake()); // wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake()); wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
trails.getChildren().add(newBoat.getTrail()); trails.getChildren().add(newBoat.getTrail());
// TODO: 1/08/17 Make this less vile to look at. // TODO: 1/08/17 Make this less vile to look at.
clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> { yacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
BoatObject bo = boatObjects.get(boat); BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon); Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir); bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
@@ -384,11 +403,11 @@ public class GameView extends Pane {
}); });
} }
private void createAndBindAnnotationBox(ClientYacht clientYacht, Paint colour) { private void createAndBindAnnotationBox(ClientYacht yacht, Paint colour) {
AnnotationBox newAnnotation = new AnnotationBox(); AnnotationBox newAnnotation = new AnnotationBox();
newAnnotation.setFill(colour); newAnnotation.setFill(colour);
newAnnotation.addAnnotation( newAnnotation.addAnnotation(
"name", "Player: " + clientYacht.getShortName() "name", "Player: " + yacht.getShortName()
); );
// newAnnotation.addAnnotation( // newAnnotation.addAnnotation(
// "velocity", // "velocity",
@@ -411,7 +430,7 @@ public class GameView extends Pane {
// return format.format(time); // return format.format(time);
// } // }
// ); // );
annotations.put(clientYacht, newAnnotation); annotations.put(yacht, newAnnotation);
} }
private void drawFps(Double fps) { private void drawFps(Double fps) {
@@ -613,7 +632,6 @@ public class GameView extends Pane {
timer.stop(); timer.stop();
} }
public void setWindDir(double windDir) { public void setWindDir(double windDir) {
this.windDir = windDir; this.windDir = windDir;
} }
@@ -626,11 +644,18 @@ public class GameView extends Pane {
return playerYacht; return playerYacht;
} }
public void setBoatAsPlayer (ClientYacht playerYacht) { public void setBoatAsPlayer (ClientYacht playerYacht) {
this.playerYacht = playerYacht; this.playerYacht = playerYacht;
this.playerYacht.toggleSail(); this.playerYacht.toggleSail();
boatObjects.get(playerYacht).setAsPlayer(); boatObjects.get(playerYacht).setAsPlayer();
CompoundMark currentMark = course.get(playerYacht.getLegNumber());
for (Mark mark : currentMark.getMarks()) {
markerObjects.get(mark).showExitArrow();
}
CompoundMark destination = course.get(playerYacht.getLegNumber() + 1);
for (Mark mark : destination.getMarks()) {
markerObjects.get(mark).showEnterArrow();
}
annotations.get(playerYacht).addAnnotation( annotations.get(playerYacht).addAnnotation(
"velocity", "velocity",
playerYacht.getVelocityProperty(), playerYacht.getVelocityProperty(),
@@ -642,6 +667,24 @@ public class GameView extends Pane {
annotationsGroup.getChildren().remove(annotations.get(playerYacht)); annotationsGroup.getChildren().remove(annotations.get(playerYacht));
gameObjects.add(annotations.get(playerYacht)); gameObjects.add(annotations.get(playerYacht));
}); });
playerYacht.addMarkRoundingListener(this::updateMarkArrows);
}
private void updateMarkArrows (ClientYacht yacht, CompoundMark compoundMark, int legNumber) {
//Only show arrows for this and next leg.
for (Mark mark : compoundMark.getMarks()) {
markerObjects.get(mark).showExitArrow();
}
CompoundMark nextMark = course.get(legNumber);
for (Mark mark : nextMark.getMarks()) {
markerObjects.get(mark).showEnterArrow();
}
if (legNumber - 2 >= 0) {
CompoundMark lastMark = course.get(Math.max(0, legNumber - 2));
for (Mark mark : lastMark.getMarks()) {
markerObjects.get(mark).hideAllArows();
}
}
} }
/** /**
@@ -651,32 +694,30 @@ public class GameView extends Pane {
* @param collisionPoint yacht collision point * @param collisionPoint yacht collision point
*/ */
public void drawCollision(GeoPoint collisionPoint) { public void drawCollision(GeoPoint collisionPoint) {
Platform.runLater(() -> { Point2D point = findScaledXY(collisionPoint);
Point2D point = findScaledXY(collisionPoint); double circleRadius = 0.0;
double circleRadius = 0.0; Circle circle = new Circle(point.getX(), point.getY(), circleRadius, Color.RED);
Circle circle = new Circle(point.getX(), point.getY(), circleRadius, Color.RED);
gameObjects.add(circle);
circle.setFill(Color.TRANSPARENT); circle.setFill(Color.TRANSPARENT);
circle.setStroke(Color.RED); circle.setStroke(Color.RED);
circle.setStrokeWidth(3); circle.setStrokeWidth(3);
Timeline timeline = new Timeline(); Timeline timeline = new Timeline();
timeline.setCycleCount(1); timeline.setCycleCount(1);
KeyFrame keyframe1 = new KeyFrame(Duration.ZERO, KeyFrame keyframe1 = new KeyFrame(Duration.ZERO,
new KeyValue(circle.radiusProperty(), 0), new KeyValue(circle.radiusProperty(), 0),
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT)); new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
KeyFrame keyFrame2 = new KeyFrame(new Duration(1000), KeyFrame keyFrame2 = new KeyFrame(new Duration(1000),
new KeyValue(circle.radiusProperty(), 50), new KeyValue(circle.radiusProperty(), 50),
new KeyValue(circle.strokeProperty(), Color.RED)); new KeyValue(circle.strokeProperty(), Color.RED));
KeyFrame keyFrame3 = new KeyFrame(new Duration(1500), KeyFrame keyFrame3 = new KeyFrame(new Duration(1500),
new KeyValue(circle.strokeProperty(), Color.TRANSPARENT)); new KeyValue(circle.strokeProperty(), Color.TRANSPARENT));
timeline.getKeyFrames().addAll(keyframe1, keyFrame2, keyFrame3); timeline.getKeyFrames().addAll(keyframe1, keyFrame2, keyFrame3);
timeline.play();
timeline.setOnFinished(event -> gameObjects.remove(circle)); Platform.runLater(() -> gameObjects.add(circle));
}); timeline.setOnFinished(event -> Platform.runLater(() -> gameObjects.remove(circle)));
timeline.play();
} }
} }
@@ -63,7 +63,7 @@ public class FinishScreenViewController implements Initializable {
public void setFinishers(List<ClientYacht> participants) { public void setFinishers(List<ClientYacht> participants) {
List<ClientYacht> sorted = new ArrayList<>(participants); List<ClientYacht> sorted = new ArrayList<>(participants);
sorted.sort(Comparator.comparingInt(ClientYacht::getPositionInteger)); sorted.sort(Comparator.comparingInt(ClientYacht::getPlacing));
finishOrderTable.getItems().setAll(sorted); finishOrderTable.getItems().setAll(sorted);
} }
@@ -34,8 +34,8 @@ import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import seng302.model.ClientYacht;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.ClientYacht;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
@@ -79,6 +79,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private GameView gameView; private GameView gameView;
private RaceState raceState; private RaceState raceState;
private Timeline timerTimeline;
private Timer timer = new Timer(); private Timer timer = new Timer();
private List<Series<String, Double>> sparkLineData = new ArrayList<>(); private List<Series<String, Double>> sparkLineData = new ArrayList<>();
private ImportantAnnotationsState importantAnnotations; private ImportantAnnotationsState importantAnnotations;
@@ -100,8 +101,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
public void loadRace ( public void loadRace (
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState, Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState, ClientYacht player
ClientYacht player
) { ) {
this.participants = participants; this.participants = participants;
this.courseData = raceData; this.courseData = raceData;
@@ -123,6 +123,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
); );
gameView.setBoatAsPlayer(player); gameView.setBoatAsPlayer(player);
gameView.startRace(); gameView.startRace();
raceState.addCollisionListener(gameView::drawCollision);
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
gameView.setWindDir(newDirection.doubleValue());
updateWindDirection(newDirection.doubleValue());
});
for (ClientYacht yacht : participants.values()) {
yacht.placingProperty().addListener((obs, oldPlacing, newPlacing) -> {
updateOrder();
updateSparkLine();
});
}
} }
/** /**
@@ -208,10 +219,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Used to add any new yachts into the race that may have started late or not have had data * Used to add any new yachts into the race that may have started late or not have had data received yet
* received yet
*/ */
private void updateSparkLine() { private void updateSparkLine(){
// TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed. // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
// Collect the racing yachts that aren't already in the chart // Collect the racing yachts that aren't already in the chart
sparkLineData.clear(); sparkLineData.clear();
@@ -219,40 +229,39 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// Create a new data series for new yachts // Create a new data series for new yachts
sparkLineCandidates sparkLineCandidates
.stream() .stream()
.filter(yacht -> yacht.getPositionInteger() != null) .filter(yacht -> yacht.getPlacing() != null)
.forEach(yacht -> { .forEach(yacht -> {
Series<String, Double> yachtData = new Series<>(); Series<String, Double> yachtData = new Series<>();
yachtData.setName(yacht.getSourceId().toString()); yachtData.setName(yacht.getSourceId().toString());
yachtData.getData().add( yachtData.getData().add(
new XYChart.Data<>( new XYChart.Data<>(
Integer.toString(yacht.getLegNumber()), Integer.toString(yacht.getLegNumber()),
1.0 + participants.size() - yacht.getPositionInteger() 1.0 + participants.size() - yacht.getPlacing()
) )
); );
sparkLineData.add(yachtData); sparkLineData.add(yachtData);
}); });
// Lambda function to sort the series in order of leg (later legs shown more to the right) // Lambda function to sort the series in order of leg (later legs shown more to the right)
sparkLineData.sort((o1, o2) -> { sparkLineData.sort((o1, o2) -> {
Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size() - 1).getXValue()); Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size() - 1).getXValue()); Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
if (leg2 < leg1) { if (leg2 < leg1){
return 1; return 1;
} else { } else {
return -1; return -1;
} }
}); });
// Adds the new data series to the sparkline (and set the colour of the series) // Adds the new data series to the sparkline (and set the colour of the series)
Platform.runLater(() -> Platform.runLater(() -> {
sparkLineData sparkLineData
.stream() .stream()
.filter(spark -> !raceSparkLine.getData().contains(spark)) .filter(spark -> !raceSparkLine.getData().contains(spark))
.forEach(spark -> { .forEach(spark -> {
raceSparkLine.getData().add(spark); raceSparkLine.getData().add(spark);
spark.getNode().lookup(".chart-series-line") spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
.setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName())); });
}) });
);
} }
private void initialiseSparkLine() { private void initialiseSparkLine() {
@@ -262,15 +271,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Updates the yachts sparkline of the desired yacht and using the new leg number * Updates the yachts sparkline of the desired yacht and using the new leg number
* @param clientYacht The yacht to be updated on the sparkline * @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to * @param legNumber the leg number that the position will be assigned to
*/ */
void updateYachtPositionSparkline(ClientYacht clientYacht, Integer legNumber) { void updateClientYachtPositionSparkline(ClientYacht yacht, Integer legNumber){
for (XYChart.Series<String, Double> positionData : sparkLineData) { for (XYChart.Series<String, Double> positionData : sparkLineData) {
positionData.getData().add( positionData.getData().add(
new Data<>( new Data<>(
Integer.toString(legNumber), Integer.toString(legNumber),
1.0 + participants.size() - clientYacht.getPositionInteger() 1.0 + participants.size() - yacht.getPlacing()
) )
); );
} }
@@ -278,7 +287,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// positionData.getData().add( // positionData.getData().add(
// new XYChart.Data<>( // new XYChart.Data<>(
// Integer.toString(legNumber), // Integer.toString(legNumber),
// 1.0 + participants.size() - yacht.getPosition() // 1.0 + participants.size() - yacht.getPlacing()
// ) // )
// ); // );
} }
@@ -286,52 +295,47 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* gets the rgb string of the yachts colour to use for the chart via css * gets the rgb string of the yachts colour to use for the chart via css
*
* @param yachtId id of yacht passed in to get the yachts colour * @param yachtId id of yacht passed in to get the yachts colour
* @return the colour as an rgb string * @return the colour as an rgb string
*/ */
private String getBoatColorAsRGB(String yachtId) { private String getBoatColorAsRGB(String yachtId){
Color color = participants.get(Integer.valueOf(yachtId)).getColour(); Color color = participants.get(Integer.valueOf(yachtId)).getColour();
if (color == null) { if (color == null){
return String.format("#%02X%02X%02X", 255, 255, 255); return String.format("#%02X%02X%02X",255,255,255);
} }
return String.format("#%02X%02X%02X", return String.format( "#%02X%02X%02X",
(int) (color.getRed() * 255), (int)( color.getRed() * 255 ),
(int) (color.getGreen() * 255), (int)( color.getGreen() * 255 ),
(int) (color.getBlue() * 255) (int)( color.getBlue() * 255 )
); );
} }
/** /**
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht * Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly. Updates of * orderings etc.. which are dependent on the info from the stream parser constantly.
* each of these attributes are called ONCE EACH SECOND * Updates of each of these attributes are called ONCE EACH SECOND
*/ */
private void initializeUpdateTimer() { private void initializeUpdateTimer() {
timer.scheduleAtFixedRate(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
updateRaceTime(); updateRaceTime();
updateWindDirection();
updateOrder();
// updateSparkLine();
} }
}, 0, 1000); }, 0, 1000);
} }
/** /**
* Iterates over all corners until ones SeqID matches with the yachts current leg number. Then * Iterates over all corners until ones SeqID matches with the yachts current leg number.
* it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark Returns * Then it gets the compoundMarkID of that corner and uses it to fetch the appropriate mark
* null if no next mark found. * Returns null if no next mark found.
*
* @param bg The BoatGroup to find the next mark of * @param bg The BoatGroup to find the next mark of
* @return The next Mark or null if none found * @return The next Mark or null if none found
*/ */
private Mark getNextMark(BoatObject bg) { private Mark getNextMark(BoatObject bg) {
// TODO: 1/08/17 Move to GameView // TODO: 1/08/17 Move to GameView
// //
// Integer legNumber = bg.getYacht().getLegNumber(); // Integer legNumber = bg.getClientYacht().getLegNumber();
// List<Corner> markSequence = courseData.getMarkSequence(); // List<Corner> markSequence = courseData.getMarkSequence();
// //
// if (legNumber == 0) { // if (legNumber == 0) {
@@ -352,10 +356,11 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Updates the wind direction arrow and text as from info from the StreamParser * Updates the wind direction arrow and text as from info from the StreamParser
* @param direction the from north angle of the wind.
*/ */
private void updateWindDirection() { private void updateWindDirection(double direction) {
windDirectionText.setText(String.format("%.1f°", raceState.getWindDirection())); windDirectionText.setText(String.format("%.1f°", direction));
windArrowText.setRotate(raceState.getWindDirection()); windArrowText.setRotate(direction);
} }
@@ -376,25 +381,20 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
* section * section
*/ */
private void updateOrder() { private void updateOrder() {
// positionVbox.getChildren().removeAll();
// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// list of racing yacht id
List<ClientYacht> sorted = new ArrayList<>(participants.values()); List<ClientYacht> sorted = new ArrayList<>(participants.values());
sorted.sort(Comparator.comparingInt(ClientYacht::getPositionInteger)); sorted.sort(Comparator.comparingInt(ClientYacht::getPlacing));
List<Text> vboxEntries = new ArrayList<>(); List<Text> vboxEntries = new ArrayList<>();
for (ClientYacht clientYacht : sorted) { for (ClientYacht yacht : sorted) {
// System.out.println("yacht == null " + String.valueOf(yacht == null)); if (yacht.getBoatStatus() == 3) { // 3 is finish status
if (clientYacht.getBoatStatus() == 3) { // 3 is finish status Text textToAdd = new Text(yacht.getPlacing() + ". " +
Text textToAdd = new Text(clientYacht.getPositionInteger() + ". " + yacht.getShortName() + " (Finished)");
clientYacht.getShortName() + " (Finished)");
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
vboxEntries.add(textToAdd); vboxEntries.add(textToAdd);
} else { } else {
Text textToAdd = new Text(clientYacht.getPositionInteger() + ". " + Text textToAdd = new Text(yacht.getPlacing() + ". " +
clientYacht.getShortName() + " "); yacht.getShortName() + " ");
textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setFill(Paint.valueOf("#d3d3d3"));
textToAdd.setStyle(""); textToAdd.setStyle("");
vboxEntries.add(textToAdd); vboxEntries.add(textToAdd);
@@ -403,13 +403,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
Platform.runLater(() -> Platform.runLater(() ->
positionVbox.getChildren().setAll(vboxEntries) positionVbox.getChildren().setAll(vboxEntries)
); );
// participants.forEach((id, yacht) ->{
// Text textToAdd = new Text(yacht.getPosition() + ". " +
// yacht.getShortName() + " ");
// textToAdd.setFill(Paint.valueOf("#d3d3d3"));
// textToAdd.setStyle("");
// positionVbox.getChildren().add(textToAdd);
// });
} }
@@ -478,17 +471,15 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
private Point2D getPointRotation(Point2D ref, Double distance, Double angle) { private Point2D getPointRotation(Point2D ref, Double distance, Double angle){
Double newX = ref.getX() + (ref.getX() + distance - ref.getX()) * Math.cos(angle) Double newX = ref.getX() + (ref.getX() + distance -ref.getX())*Math.cos(angle) - (ref.getY() + distance -ref.getY())*Math.sin(angle);
- (ref.getY() + distance - ref.getY()) * Math.sin(angle); Double newY = ref.getY() + (ref.getX() + distance -ref.getX())*Math.sin(angle) + (ref.getY() + distance -ref.getY())*Math.cos(angle);
Double newY = ref.getY() + (ref.getX() + distance - ref.getX()) * Math.sin(angle)
+ (ref.getY() + distance - ref.getY()) * Math.cos(angle);
return new Point2D(newX, newY); return new Point2D(newX, newY);
} }
public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) { public Line makeLeftLayline(Point2D startPoint, Double layLineAngle, Double baseAngle) {
Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle); Point2D ep = getPointRotation(startPoint, 50.0, baseAngle + layLineAngle);
Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY()); Line line = new Line(startPoint.getX(), startPoint.getY(), ep.getX(), ep.getY());
@@ -507,8 +498,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Initialised the combo box with any yachts currently in the race and adds the required * Initialised the combo box with any yachts currently in the race and adds the required listener
* listener for the combobox to take action upon selection * for the combobox to take action upon selection
*/ */
private void initialiseBoatSelectionComboBox() { private void initialiseBoatSelectionComboBox() {
yachtSelectionComboBox.setItems( yachtSelectionComboBox.setItems(
@@ -545,7 +536,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
TimeUnit.MILLISECONDS.toHours(milliseconds), TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour TimeUnit.MILLISECONDS.toMinutes(milliseconds) % 60, //Modulus 60 minutes per hour
TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute TimeUnit.MILLISECONDS.toSeconds(milliseconds) % 60 //Modulus 60 seconds per minute
); );
} }
private void setAnnotations(Integer annotationLevel) { private void setAnnotations(Integer annotationLevel) {
@@ -580,9 +571,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
/** /**
* Sets all the annotations of the selected yacht to be visible and all others to be hidden * Sets all the annotations of the selected yacht to be visible and all others to be hidden
* *
* @param clientYacht The yacht for which we want to view all annotations * @param yacht The yacht for which we want to view all annotations
*/ */
private void setSelectedBoat(ClientYacht clientYacht) { private void setSelectedBoat(ClientYacht yacht) {
// for (BoatObject bg : gameViewController.getBoatGroups()) { // for (BoatObject bg : gameViewController.getBoatGroups()) {
// //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we // //We need to iterate over all race groups to get the matching yacht group belonging to this yacht if we
// //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup. // //are to toggle its annotations, there is no other backwards knowledge of a yacht to its yachtgroup.
@@ -596,23 +587,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
// } // }
} }
public void updateRaceData(RaceXMLData raceData) { public void updateRaceData (RaceXMLData raceData) {
this.courseData = raceData; this.courseData = raceData;
gameView.updateBorder(raceData.getCourseLimit()); gameView.updateBorder(raceData.getCourseLimit());
} }
/**
* Called by game client after receiving yacht event packet. Parameter subject id is the
* offending yacht. This function in turn will pass the yacht location to game view to display a
* collision alert.
*
* @param subjectId source id of offending yacht
*/
public void showCollision(Long subjectId) {
gameView.drawCollision(participants.get((int) (long) subjectId).getLocation());
}
public GameView getGameView() {
return gameView;
}
} }
@@ -11,6 +11,7 @@ import javafx.scene.paint.Paint;
import javafx.scene.shape.Line; import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon; import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline; import javafx.scene.shape.Polyline;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.transform.Rotate; import javafx.scene.transform.Rotate;
/** /**
@@ -352,7 +353,8 @@ public class BoatObject extends Group {
BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75 BOAT_WIDTH / 1.75, BOAT_HEIGHT / 1.75
); );
boatPoly.setStroke(Color.BLACK); boatPoly.setStroke(Color.BLACK);
boatPoly.setStrokeWidth(3); boatPoly.setStrokeWidth(2);
boatPoly.setStrokeLineCap(StrokeLineCap.ROUND);
isPlayer = true; isPlayer = true;
animateSail(); animateSail();
} }
@@ -32,15 +32,29 @@ public class Marker extends Group {
public void constructArrows(MarkArrowFactory.RoundingSide roundingSide, double entryAngle, double exitAngle) { public void constructArrows(MarkArrowFactory.RoundingSide roundingSide, double entryAngle, double exitAngle) {
enterArrow = MarkArrowFactory.constructEntryArrow(roundingSide, entryAngle, exitAngle, colour); enterArrow = MarkArrowFactory.constructEntryArrow(roundingSide, entryAngle, exitAngle, colour);
exitArrow = MarkArrowFactory.constructExitArrow(roundingSide, exitAngle, colour); exitArrow = MarkArrowFactory.constructExitArrow(roundingSide, exitAngle, colour);
Platform.runLater(() -> this.getChildren().add(enterArrow));
// Platform.runLater(() -> this.getChildren().add(exitArrow));
} }
public void showEnterArrow () { public void showEnterArrow () {
Platform.runLater(() -> this.getChildren().setAll(enterArrow)); if (!this.getChildren().contains(enterArrow)) {
Platform.runLater(() -> {
this.getChildren().remove(exitArrow);
this.getChildren().add(enterArrow);
});
}
} }
public void showExitArrow () { public void showExitArrow () {
Platform.runLater(() -> this.getChildren().setAll(exitArrow)); if (!this.getChildren().contains(exitArrow)) {
Platform.runLater(() -> {
this.getChildren().remove(enterArrow);
this.getChildren().add(exitArrow);
});
}
}
public void hideAllArows () {
Platform.runLater(() -> {
this.getChildren().removeAll(enterArrow, exitArrow);
});
} }
} }
@@ -3,7 +3,7 @@ package seng302.gameServer.server;
import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertEquals;
import org.junit.Test; import org.junit.Test;
import seng302.gameServer.server.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
/** /**
* Test conversions used by the boat location messages * Test conversions used by the boat location messages
@@ -3,8 +3,8 @@ package seng302.gameServer.server;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import org.junit.Test; import org.junit.Test;
import seng302.gameServer.server.messages.Header; import seng302.gameServer.messages.Header;
import seng302.gameServer.server.messages.MessageType; import seng302.gameServer.messages.MessageType;
/** /**
* Tests message header * Tests message header
@@ -4,9 +4,9 @@ import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import org.junit.Test; import org.junit.Test;
import seng302.gameServer.server.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.server.messages.XMLMessage; import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.server.messages.XMLMessageSubType; import seng302.gameServer.messages.XMLMessageSubType;
public class TestMessage { public class TestMessage {
private static int XML_MESSAGE_LEN = 14; private static int XML_MESSAGE_LEN = 14;
+1 -1
View File
@@ -8,7 +8,7 @@ import org.junit.Assert;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
import seng302.gameServer.server.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.visualiser.ClientToServerThread; import seng302.visualiser.ClientToServerThread;