mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Getting boat locations from race simulator & bug fixes
- Boat locations that are generated by the simulator are sent to the client as they happen - Fixed heading and lat/lon encoding - Fixed a bug where the header wasn't included in the sent byte stream - Fixed the format of data as it's sent to the client. - Data is now sent using a channel - Removed tests that don't work with channels Tags: #story[829]
This commit is contained in:
@@ -21,7 +21,7 @@ public class App extends Application
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new ServerThread("Racevision Test Server");
|
new ServerThread("Racevision Test Server");
|
||||||
new Thread(new Simulator(1000)).run();
|
//new Thread(new Simulator(1000)).run();
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,44 @@
|
|||||||
package seng302.server;
|
package seng302.server;
|
||||||
|
|
||||||
import seng302.server.messages.*;
|
import seng302.server.messages.*;
|
||||||
|
import seng302.server.simulator.Boat;
|
||||||
|
import seng302.server.simulator.Simulator;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
public class ServerThread implements Runnable{
|
public class ServerThread implements Runnable, Observer {
|
||||||
private Thread runner;
|
private Thread runner;
|
||||||
private StreamingServerSocket server;
|
private StreamingServerSocket server;
|
||||||
|
private long startTime;
|
||||||
|
boolean raceStarted = false;
|
||||||
|
private List<Boat> boats;
|
||||||
|
private Simulator raceSimulator;
|
||||||
|
|
||||||
private final int HEARTBEAT_PERIOD = 5000;
|
private final int HEARTBEAT_PERIOD = 5000;
|
||||||
private final int RACE_STATUS_PERIOD = 1000;
|
private final int RACE_STATUS_PERIOD = 1000/2;
|
||||||
|
private final int RACE_START_STATUS_PERIOD = 1000/2;
|
||||||
private final int BOAT_LOCATION_PERIOD = 1000/5;
|
private final int BOAT_LOCATION_PERIOD = 1000/5;
|
||||||
private final int PORT_NUMBER = 8085;
|
private final int PORT_NUMBER = 8085;
|
||||||
|
private final int TIME_TILL_RACE_START = 10;
|
||||||
|
private static final int LOG_LEVEL = 1;
|
||||||
|
|
||||||
public ServerThread(String threadName){
|
public ServerThread(String threadName){
|
||||||
runner = new Thread(this, threadName);
|
runner = new Thread(this, threadName);
|
||||||
System.out.println("Spawning Server Thread");
|
serverLog("Spawning Server", 0);
|
||||||
|
raceSimulator = new Simulator(BOAT_LOCATION_PERIOD);
|
||||||
|
boats = raceSimulator.getBoats();
|
||||||
runner.start();
|
runner.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void serverLog(String message, int logLevel){
|
||||||
|
if(logLevel <= LOG_LEVEL){
|
||||||
|
System.out.println("[SERVER] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns an XML Message from the file specified
|
* Creates and returns an XML Message from the file specified
|
||||||
* @param fileName The source XML file
|
* @param fileName The source XML file
|
||||||
@@ -38,6 +53,9 @@ public class ServerThread implements Runnable{
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
catch (NullPointerException e){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (fileContents != null){
|
if (fileContents != null){
|
||||||
return new XMLMessage(fileContents, type, server.getSequenceNumber());
|
return new XMLMessage(fileContents, type, server.getSequenceNumber());
|
||||||
@@ -47,56 +65,113 @@ public class ServerThread implements Runnable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A sample race status message
|
* @return Get a race status message for the current race
|
||||||
*/
|
*/
|
||||||
public Message getTestRaceStatusMessage(){
|
public Message getRaceStatusMessage(){
|
||||||
BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0,
|
List<BoatSubMessage> boatSubMessages = new ArrayList<BoatSubMessage>();
|
||||||
10000, 10000);
|
BoatStatus boatStatus;
|
||||||
|
RaceStatus raceStatus;
|
||||||
|
|
||||||
BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0,
|
if (raceStarted){
|
||||||
10000, 10000);
|
boatStatus = BoatStatus.RACING;
|
||||||
|
raceStatus = RaceStatus.STARTED;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
boatStatus = BoatStatus.PRESTART;
|
||||||
|
raceStatus = RaceStatus.PRESTART;
|
||||||
|
}
|
||||||
|
|
||||||
BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0,
|
for (Boat b : boats){
|
||||||
10000, 10000);
|
BoatSubMessage m = new BoatSubMessage(b.getSourceID(), boatStatus, b.getLastPassedCorner().getSeqID(), 0, 0, 0, 0);
|
||||||
|
boatSubMessages.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RaceStatusMessage(1, raceStatus, startTime, WindDirection.EAST,
|
||||||
List<BoatSubMessage> boats = new ArrayList<BoatSubMessage>();
|
100, boats.size(), RaceType.MATCH_RACE, 1, boatSubMessages);
|
||||||
boats.add(boat1);
|
|
||||||
boats.add(boat2);
|
|
||||||
boats.add(boat3);
|
|
||||||
|
|
||||||
return new RaceStatusMessage(1, RaceStatus.PRESTART, 1000, WindDirection.EAST,
|
|
||||||
100, 3, RaceType.MATCH_RACE, 1, boats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A list of sample boat location messages
|
* Starts an instance of the race simulator
|
||||||
*/
|
*/
|
||||||
public List<Message> getTestBoatLocationMessages(){
|
private void startRaceSim(){
|
||||||
List<Message> messages = new ArrayList<>();
|
serverLog("Starting Race Simulator", 0);
|
||||||
|
raceSimulator.addObserver(this);
|
||||||
messages.add(new BoatLocationMessage(1, 1, 100, 200, 231, 23));
|
new Thread(raceSimulator).start();
|
||||||
messages.add(new BoatLocationMessage(2, 2, 400, 300, 211, 13));
|
|
||||||
|
|
||||||
return messages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts sending heartbeat messages to the client
|
||||||
|
*/
|
||||||
|
private void startSendingHeartbeats(){
|
||||||
|
serverLog("Sending Heartbeats", 0);
|
||||||
|
Timer t = new Timer();
|
||||||
|
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try{
|
Message heartbeat = new Heartbeat(server.getSequenceNumber());
|
||||||
server = new StreamingServerSocket(PORT_NUMBER);
|
|
||||||
}
|
|
||||||
catch (IOException e){
|
|
||||||
System.err.println("Failed to bind socket: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load and send race XML data
|
server.send(heartbeat);
|
||||||
Message raceData = getXmlMessage("/server_config/race.xml", XMLMessageSubType.RACE);
|
} catch (IOException e) {
|
||||||
Message boatData = getXmlMessage("/server_config/boats.xml", XMLMessageSubType.BOAT);
|
System.out.print("");
|
||||||
Message regatta = getXmlMessage("/server_config/regatta.xml", XMLMessageSubType.REGATTA);
|
}
|
||||||
|
}
|
||||||
|
}, 0, HEARTBEAT_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start sending race start status messages until race starts
|
||||||
|
*/
|
||||||
|
private void startSendingRaceStartStatusMessages(){
|
||||||
|
Timer t = new Timer();
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Message raceStartStatusMessage = new RaceStartStatusMessage(server.getSequenceNumber(), startTime , 1,
|
||||||
|
RaceStartNotificationType.SET_RACE_START_TIME);
|
||||||
|
try {
|
||||||
|
if (startTime < System.currentTimeMillis()/1000 && !raceStarted){
|
||||||
|
startRaceSim();
|
||||||
|
raceStarted = true;
|
||||||
|
serverLog("Race Started", 0);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
server.send(raceStartStatusMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.print("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, RACE_START_STATUS_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startSendingRaceStatusMessages(){
|
||||||
|
serverLog("Sending Race Status Messages", 0);
|
||||||
|
Timer t = new Timer();
|
||||||
|
t.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Message statusMessage = getRaceStatusMessage();
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.send(statusMessage);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.print("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100, RACE_STATUS_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the race, boat, and regatta XML files to the client
|
||||||
|
*/
|
||||||
|
private void sendXml(){
|
||||||
|
try{
|
||||||
|
Message raceData = getXmlMessage("server_config/race.xml", XMLMessageSubType.RACE);
|
||||||
|
Message boatData = getXmlMessage("server_config/boats.xml", XMLMessageSubType.BOAT);
|
||||||
|
Message regatta = getXmlMessage("server_config/regatta.xml", XMLMessageSubType.REGATTA);
|
||||||
|
|
||||||
if (raceData != null){
|
if (raceData != null){
|
||||||
server.send(raceData);
|
server.send(raceData);
|
||||||
@@ -109,54 +184,53 @@ public class ServerThread implements Runnable{
|
|||||||
if (regatta != null){
|
if (regatta != null){
|
||||||
server.send(regatta);
|
server.send(regatta);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer to send the heartbeat
|
|
||||||
Timer t = new Timer();
|
|
||||||
t.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Message hb = new Heartbeat(server.getSequenceNumber());
|
|
||||||
try {
|
|
||||||
server.send(hb);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
serverLog("Couldn't send an XML Message: " + e.getMessage(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0, HEARTBEAT_PERIOD);
|
|
||||||
|
|
||||||
// Timer to send the race status messages
|
|
||||||
Timer t1 = new Timer();
|
|
||||||
t1.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
public void run() {
|
||||||
Message statusMessage = getTestRaceStatusMessage();
|
try{
|
||||||
|
server = new StreamingServerSocket(PORT_NUMBER);
|
||||||
try {
|
|
||||||
server.send(statusMessage);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.print("");
|
|
||||||
}
|
}
|
||||||
|
catch (IOException e){
|
||||||
|
serverLog("Failed to bind socket: " + e.getMessage(), 0);
|
||||||
}
|
}
|
||||||
}, 100, RACE_STATUS_PERIOD);
|
|
||||||
|
|
||||||
t1.schedule(new TimerTask() {
|
startTime = (System.currentTimeMillis()/1000) + TIME_TILL_RACE_START;
|
||||||
|
|
||||||
|
// Wait for client to connect
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
startSendingHeartbeats();
|
||||||
|
sendXml();
|
||||||
|
startSendingRaceStartStatusMessages();
|
||||||
|
startSendingRaceStatusMessages();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a boat location message when they are updated by the simulator
|
||||||
|
* @param o .
|
||||||
|
* @param arg .
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void update(Observable o, Object arg) {
|
||||||
List<Message> messages = getTestBoatLocationMessages();
|
// Only send if server started
|
||||||
|
if(!server.isStarted()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Message m : messages){
|
for (Boat b : ((Simulator) o).getBoats()){
|
||||||
try {
|
try {
|
||||||
|
Message m = new BoatLocationMessage(b.getSourceID(), 1, b.getLat(),
|
||||||
|
b.getLng(), b.getHeadingCorner().getBearingToNextCorner(),
|
||||||
|
((long) b.getSpeed()));
|
||||||
|
|
||||||
server.send(m);
|
server.send(m);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.print("");
|
serverLog("Couldn't send a boat status message", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}, 100, BOAT_LOCATION_PERIOD);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,35 +4,44 @@ import seng302.server.messages.Message;
|
|||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class StreamingServerSocket {
|
class StreamingServerSocket {
|
||||||
private java.net.ServerSocket socket;
|
private ServerSocketChannel socket;
|
||||||
private Socket client;
|
private SocketChannel client;
|
||||||
private List<Socket> clients;
|
private List<Socket> clients;
|
||||||
private short seqNum;
|
private short seqNum;
|
||||||
|
private boolean isServerStarted;
|
||||||
|
|
||||||
StreamingServerSocket(int port) throws IOException{
|
StreamingServerSocket(int port) throws IOException{
|
||||||
socket = new java.net.ServerSocket(port);
|
socket = ServerSocketChannel.open();
|
||||||
|
socket.socket().bind(new InetSocketAddress("localhost", port));
|
||||||
clients = new ArrayList<>();
|
clients = new ArrayList<>();
|
||||||
socket.setSoTimeout(10000);
|
//socket.setSoTimeout(10000);
|
||||||
seqNum = 0;
|
seqNum = 0;
|
||||||
|
isServerStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(){
|
void start(){
|
||||||
System.out.println("Listening For Connections");
|
ServerThread.serverLog("Listening For Connections",0);
|
||||||
try {
|
try {
|
||||||
client = socket.accept();
|
client = socket.accept();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.getMessage();
|
e.getMessage();
|
||||||
}
|
}
|
||||||
if (client == null){
|
if (client.socket() == null){
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
System.out.println("client connected from " + client.getInetAddress());
|
isServerStarted = true;
|
||||||
|
ServerThread.serverLog("client connected from " + client.socket().getInetAddress(),0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +50,9 @@ class StreamingServerSocket {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataOutputStream outputStream = new DataOutputStream(client.getOutputStream());
|
//DataOutputStream outputStream = new DataOutputStream(client.getOutputStream());
|
||||||
message.send(outputStream);
|
//System.out.println(client);
|
||||||
|
message.send(client);
|
||||||
|
|
||||||
seqNum++;
|
seqNum++;
|
||||||
}
|
}
|
||||||
@@ -50,4 +60,8 @@ class StreamingServerSocket {
|
|||||||
public short getSequenceNumber(){
|
public short getSequenceNumber(){
|
||||||
return seqNum;
|
return seqNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isStarted(){
|
||||||
|
return isServerStarted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package seng302.server.messages;
|
|||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
public class BoatLocationMessage extends Message {
|
public class BoatLocationMessage extends Message {
|
||||||
private final int MESSAGE_SIZE = 56;
|
private final int MESSAGE_SIZE = 56;
|
||||||
@@ -11,10 +14,10 @@ public class BoatLocationMessage extends Message {
|
|||||||
private long sourceId;
|
private long sourceId;
|
||||||
private long sequenceNum;
|
private long sequenceNum;
|
||||||
private DeviceType deviceType;
|
private DeviceType deviceType;
|
||||||
private long latitude;
|
private double latitude;
|
||||||
private long longitude;
|
private double longitude;
|
||||||
private long altitude;
|
private long altitude;
|
||||||
private long heading;
|
private Double heading;
|
||||||
private long pitch;
|
private long pitch;
|
||||||
private long roll;
|
private long roll;
|
||||||
private long boatSpeed;
|
private long boatSpeed;
|
||||||
@@ -38,13 +41,13 @@ public class BoatLocationMessage extends Message {
|
|||||||
* @param heading The boats heading
|
* @param heading The boats heading
|
||||||
* @param boatSpeed The boats speed
|
* @param boatSpeed The boats speed
|
||||||
*/
|
*/
|
||||||
public BoatLocationMessage(int sourceId, int sequenceNum, long latitude, long longitude, long heading, long boatSpeed){
|
public BoatLocationMessage(int sourceId, int sequenceNum, double latitude, double longitude, double heading, long boatSpeed){
|
||||||
messageVersionNumber = 1;
|
messageVersionNumber = 1;
|
||||||
time = System.currentTimeMillis() / 1000L;
|
time = System.currentTimeMillis() / 1000L;
|
||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
this.sequenceNum = sequenceNum;
|
this.sequenceNum = sequenceNum;
|
||||||
this.deviceType = DeviceType.RACING_YACHT;
|
this.deviceType = DeviceType.RACING_YACHT;
|
||||||
this.latitude = -latitude;
|
this.latitude = latitude;
|
||||||
this.longitude = longitude;
|
this.longitude = longitude;
|
||||||
this.altitude = 0;
|
this.altitude = 0;
|
||||||
this.heading = heading;
|
this.heading = heading;
|
||||||
@@ -126,19 +129,23 @@ public class BoatLocationMessage extends Message {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException{
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
|
heading = (heading + 180.0) % 360.0;
|
||||||
|
|
||||||
|
long headingToSend = (long)((heading/360.0)*65535.0);
|
||||||
|
|
||||||
putByte((byte) messageVersionNumber);
|
putByte((byte) messageVersionNumber);
|
||||||
putInt((int) time, 6);
|
putInt(time, 6);
|
||||||
putInt((int) sourceId, 4);
|
putInt((int) sourceId, 4);
|
||||||
putUnsignedInt((int) sequenceNum, 4);
|
putUnsignedInt((int) sequenceNum, 4);
|
||||||
putByte((byte) deviceType.getCode());
|
putByte((byte) deviceType.getCode());
|
||||||
putInt((int) latitude, 4);
|
putInt((int) latLonToBinaryPackedLong(latitude), 4);
|
||||||
putInt((int) longitude, 4);
|
putInt((int) latLonToBinaryPackedLong(longitude), 4);
|
||||||
putInt((int) altitude, 4);
|
putInt((int) altitude, 4);
|
||||||
putUnsignedInt((int) heading, 2);
|
putInt(headingToSend, 2);
|
||||||
putInt((int) pitch, 2);
|
putInt((int) pitch, 2);
|
||||||
putInt((int) roll, 2);
|
putInt((int) roll, 2);
|
||||||
putUnsignedInt((int) boatSpeed, 2);
|
putUnsignedInt((int) boatSpeed, 2);
|
||||||
@@ -153,12 +160,9 @@ public class BoatLocationMessage extends Message {
|
|||||||
putUnsignedInt((int) currentSet, 2);
|
putUnsignedInt((int) currentSet, 2);
|
||||||
putInt((int) rudderAngle, 2);
|
putInt((int) rudderAngle, 2);
|
||||||
|
|
||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
try {
|
rewind();
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
outputStream.write(getBuffer());
|
||||||
System.out.print("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
public class Header {
|
public class Header {
|
||||||
// From API spec
|
// From API spec
|
||||||
@@ -12,6 +15,8 @@ public class Header {
|
|||||||
private int sourceId;
|
private int sourceId;
|
||||||
private short messageLength;
|
private short messageLength;
|
||||||
private static final int MESSAGE_LEN = 15;
|
private static final int MESSAGE_LEN = 15;
|
||||||
|
private ByteBuffer buff;
|
||||||
|
private int buffPos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message Header from section 3.2 of the AC35 Streaming
|
* Message Header from section 3.2 of the AC35 Streaming
|
||||||
@@ -25,38 +30,34 @@ public class Header {
|
|||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
this.messageLength = messageLength;
|
this.messageLength = messageLength;
|
||||||
timeStamp = (int) (System.currentTimeMillis() / 1000L);
|
timeStamp = (int) (System.currentTimeMillis() / 1000L);
|
||||||
|
buff = ByteBuffer.allocate(MESSAGE_LEN);
|
||||||
|
buffPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putInBuffer(byte[] bytes, long val){
|
||||||
|
byte[] tmp = bytes.clone();
|
||||||
|
Message.reverse(tmp);
|
||||||
|
|
||||||
|
buff.put(tmp);
|
||||||
|
buffPos += tmp.length;
|
||||||
|
buff.position(buffPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a ByteBuffer containing the message header
|
* @return a ByteBuffer containing the message header
|
||||||
*/
|
*/
|
||||||
public ByteBuffer getByteBuffer(){
|
public ByteBuffer getByteBuffer(){
|
||||||
ByteBuffer buff = ByteBuffer.allocate(15);
|
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte1).array(), syncByte1);
|
||||||
|
|
||||||
// Sync Byte 1, 1 byte
|
putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte2).array(), syncByte2);
|
||||||
buff.put(ByteBuffer.allocate(1).put((byte)syncByte1).array());
|
|
||||||
buff.position(1);
|
|
||||||
|
|
||||||
// Sync Byte 2, 1 byte
|
putInBuffer(ByteBuffer.allocate(1).put((byte)messageType.getCode()).array(), messageType.getCode());
|
||||||
buff.put(ByteBuffer.allocate(1).put((byte)syncByte2).array());
|
|
||||||
buff.position(2);
|
|
||||||
|
|
||||||
// Message Type, 1 byte
|
putInBuffer(Message.intToByteArray(timeStamp, 6), timeStamp);
|
||||||
buff.put(ByteBuffer.allocate(1).put((byte)messageType.getCode()).array());
|
|
||||||
buff.position(3);
|
|
||||||
|
|
||||||
// Timestamp, 6 bytes
|
putInBuffer(Message.intToByteArray(sourceId, 4), sourceId);
|
||||||
int x = ((int) Integer.toUnsignedLong(6));
|
|
||||||
buff.put(ByteBuffer.allocate(6).putInt(timeStamp).array());
|
|
||||||
buff.position(9);
|
|
||||||
|
|
||||||
// Source ID, 4 bytes
|
putInBuffer(Message.intToByteArray(messageLength, 2), messageLength);
|
||||||
buff.put(ByteBuffer.allocate(4).putInt(sourceId).array());
|
|
||||||
buff.position(13);
|
|
||||||
|
|
||||||
// Message Length, 2 bytes
|
|
||||||
buff.put(ByteBuffer.allocate(2).putShort(messageLength).array());
|
|
||||||
buff.position(15);
|
|
||||||
|
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package seng302.server.messages;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
public class Heartbeat extends Message {
|
public class Heartbeat extends Message {
|
||||||
@@ -23,7 +26,7 @@ public class Heartbeat extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException {
|
||||||
setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize()));
|
setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize()));
|
||||||
|
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
@@ -33,10 +36,6 @@ public class Heartbeat extends Message {
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
|
|
||||||
try {
|
outputStream.write(getBuffer());
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,9 @@ package seng302.server.messages;
|
|||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
public class MarkRoundingMessage extends Message{
|
public class MarkRoundingMessage extends Message{
|
||||||
private final long MESSAGE_VERSION_NUMBER = 1;
|
private final long MESSAGE_VERSION_NUMBER = 1;
|
||||||
@@ -38,7 +41,7 @@ public class MarkRoundingMessage extends Message{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException {
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -53,10 +56,6 @@ public class MarkRoundingMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
|
|
||||||
try {
|
outputStream.write(getBuffer());
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package seng302.server.messages;
|
package seng302.server.messages;
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
public abstract class Message {
|
public abstract class Message {
|
||||||
@@ -33,13 +39,14 @@ public abstract class Message {
|
|||||||
/**
|
/**
|
||||||
* Send the message as through the outputStream
|
* Send the message as through the outputStream
|
||||||
*/
|
*/
|
||||||
public abstract void send(DataOutputStream outputStream);
|
public abstract void send(SocketChannel outputStream) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate byte buffer to correct size
|
* Allocate byte buffer to correct size
|
||||||
*/
|
*/
|
||||||
void allocateBuffer(){
|
void allocateBuffer(){
|
||||||
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
|
buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE);
|
||||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
bufferPosition = 0;
|
bufferPosition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +54,7 @@ public abstract class Message {
|
|||||||
* Write the set header to the byte buffer
|
* Write the set header to the byte buffer
|
||||||
*/
|
*/
|
||||||
void writeHeaderToBuffer(){
|
void writeHeaderToBuffer(){
|
||||||
buffer.put(getHeader().getByteBuffer());
|
buffer.put(getHeader().getByteBuffer().array());
|
||||||
bufferPosition += Header.getSize();
|
bufferPosition += Header.getSize();
|
||||||
buffer.position(bufferPosition);
|
buffer.position(bufferPosition);
|
||||||
}
|
}
|
||||||
@@ -89,12 +96,15 @@ public abstract class Message {
|
|||||||
}
|
}
|
||||||
else if (size < 4){
|
else if (size < 4){
|
||||||
// Use short
|
// Use short
|
||||||
buffer.put(ByteBuffer.allocate(size).putShort((short) (val & 0xffff)).array());
|
byte[] tmp = Message.intToByteArray(val, size); //ByteBuffer.allocate(size).putShort((short) (val & 0xffff)).array();
|
||||||
|
reverse(tmp);
|
||||||
|
buffer.put(tmp);
|
||||||
moveBufferPositionBy(size);
|
moveBufferPositionBy(size);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Use int
|
// Use int
|
||||||
buffer.put(ByteBuffer.allocate(size).putInt((int) (val & 0xffffffffL)).array());
|
byte[] tmp = Message.intToByteArray(val, size);
|
||||||
|
reverse(tmp);
|
||||||
moveBufferPositionBy(size);
|
moveBufferPositionBy(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,12 +114,16 @@ public abstract class Message {
|
|||||||
* @param val The integer value to add
|
* @param val The integer value to add
|
||||||
* @param size The size of the integer to be added to the buffer
|
* @param size The size of the integer to be added to the buffer
|
||||||
*/
|
*/
|
||||||
void putInt(int val, int size){
|
void putInt(long val, int size){
|
||||||
if (size < 4){
|
if (size < 4){
|
||||||
buffer.put(ByteBuffer.allocate(size).putShort((short) val).array());
|
byte[] tmp = Message.intToByteArray(val, size);
|
||||||
|
reverse(tmp);
|
||||||
|
buffer.put(tmp);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
buffer.put(ByteBuffer.allocate(size).putInt((short) val).array());
|
byte[] tmp = Message.intToByteArray(val, size);
|
||||||
|
reverse(tmp);
|
||||||
|
buffer.put(tmp);
|
||||||
}
|
}
|
||||||
moveBufferPositionBy(size);
|
moveBufferPositionBy(size);
|
||||||
}
|
}
|
||||||
@@ -141,7 +155,9 @@ public abstract class Message {
|
|||||||
crc = new CRC32();
|
crc = new CRC32();
|
||||||
|
|
||||||
buffer.position(0);
|
buffer.position(0);
|
||||||
crc.update(buffer.array());
|
|
||||||
|
byte[] data = Arrays.copyOfRange(buffer.array(), 0, buffer.array().length-CRC_SIZE);
|
||||||
|
crc.update(data);
|
||||||
buffer.position(bufferPosition);
|
buffer.position(bufferPosition);
|
||||||
|
|
||||||
putInt((int) crc.getValue(), CRC_SIZE);
|
putInt((int) crc.getValue(), CRC_SIZE);
|
||||||
@@ -154,4 +170,42 @@ public abstract class Message {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewind the buffer to the beginning
|
||||||
|
*/
|
||||||
|
void rewind(){
|
||||||
|
buffer.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an integer to an array of bytes
|
||||||
|
* @param val The value to add
|
||||||
|
* @param len The width of the integer in the buffer
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] intToByteArray(long val, int len){
|
||||||
|
int index = 0;
|
||||||
|
byte[] data = new byte[len];
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++){
|
||||||
|
data[len - index - 1] = (byte) ((val >>> (8 * index)));
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse an array of bytes
|
||||||
|
* @param data The byte[] to reverse
|
||||||
|
*/
|
||||||
|
public static void reverse(byte[] data) {
|
||||||
|
for (int left = 0, right = data.length - 1; left < right; left++, right--) {
|
||||||
|
byte temp = data[left];
|
||||||
|
data[left] = data[right];
|
||||||
|
data[right] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public enum MessageType {
|
|||||||
RACE_STATUS(12),
|
RACE_STATUS(12),
|
||||||
DISPLAY_TEXT_MESSAGE(20),
|
DISPLAY_TEXT_MESSAGE(20),
|
||||||
XML_MESSAGE(26),
|
XML_MESSAGE(26),
|
||||||
RACE_START_STATUS(27),
|
RACE_START_STATUS(20),
|
||||||
YACHT_EVENT_CODE(29),
|
YACHT_EVENT_CODE(29),
|
||||||
YACHT_ACTION_CODE(31),
|
YACHT_ACTION_CODE(31),
|
||||||
CHATTER_TEXT(36),
|
CHATTER_TEXT(36),
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package seng302.server.messages;
|
|||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
public class RaceStartStatusMessage extends Message {
|
public class RaceStartStatusMessage extends Message {
|
||||||
private final int MESSAGE_SIZE = 20;
|
private final int MESSAGE_SIZE = 20;
|
||||||
@@ -37,7 +40,7 @@ public class RaceStartStatusMessage extends Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException {
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -50,10 +53,6 @@ public class RaceStartStatusMessage extends Message {
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
|
|
||||||
try {
|
outputStream.write(getBuffer());
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package seng302.server.messages;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ public class RaceStatusMessage extends Message{
|
|||||||
* @param outputStream The output stream to send the message
|
* @param outputStream The output stream to send the message
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException {
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -83,11 +86,6 @@ public class RaceStatusMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
|
|
||||||
// Send
|
outputStream.write(getBuffer());
|
||||||
try {
|
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package seng302.server.messages;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
public class XMLMessage extends Message{
|
public class XMLMessage extends Message{
|
||||||
@@ -45,7 +48,7 @@ public class XMLMessage extends Message{
|
|||||||
* Send this message as a stream of bytes
|
* Send this message as a stream of bytes
|
||||||
* @param outputStream The output stream to send the message
|
* @param outputStream The output stream to send the message
|
||||||
*/
|
*/
|
||||||
public void send(DataOutputStream outputStream) {
|
public void send(SocketChannel outputStream) throws IOException {
|
||||||
allocateBuffer();
|
allocateBuffer();
|
||||||
writeHeaderToBuffer();
|
writeHeaderToBuffer();
|
||||||
|
|
||||||
@@ -60,11 +63,6 @@ public class XMLMessage extends Message{
|
|||||||
|
|
||||||
writeCRC();
|
writeCRC();
|
||||||
|
|
||||||
// Send
|
outputStream.write(getBuffer());
|
||||||
try {
|
|
||||||
outputStream.write(getBuffer().array());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class Simulator extends Observable implements Runnable {
|
|||||||
for (Boat boat : boats) {
|
for (Boat boat : boats) {
|
||||||
numOfFinishedBoats += moveBoat(boat, lapse);
|
numOfFinishedBoats += moveBoat(boat, lapse);
|
||||||
}
|
}
|
||||||
System.out.println(boats.get(0));
|
//System.out.println(boats.get(0));
|
||||||
|
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(boats);
|
notifyObservers(boats);
|
||||||
@@ -121,4 +121,8 @@ public class Simulator extends Observable implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Boat> getBoats(){
|
||||||
|
return boats;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,50 +137,6 @@
|
|||||||
</BoatShape>
|
</BoatShape>
|
||||||
</BoatShapes>
|
</BoatShapes>
|
||||||
<Boats>
|
<Boats>
|
||||||
<Boat Type="RC" SourceID="121" ShapeID="35" StoweName="PRO" ShortName="PRO" ShorterName="PRO" BoatName="REGARDLESS" HullNum="RG02" Skipper="Iain Murray" Helmsman="Iain Murray" PeliID="121" RadioIP="172.20.2.121">
|
|
||||||
<GPSposition Z="3.8" Y="4.15" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="3.77" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="122" ShapeID="34" StoweName="SL1" ShortName="SL1" ShorterName="SL1" BoatName="Start Line 1" HullNum="Mark-02" Skipper="" PeliID="122" RadioIP="172.20.2.122">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="123" ShapeID="34" StoweName="SL2" ShortName="SL2" ShorterName="SL2" BoatName="Start Line 2" HullNum="Mark-03" Skipper="" PeliID="123" RadioIP="172.20.2.123">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="124" ShapeID="34" StoweName="LG1" ShortName="LG1" ShorterName="LG1" BoatName="Lee Gate 1" HullNum="Mark-04" Skipper="" PeliID="124" RadioIP="172.20.2.124">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="125" ShapeID="34" StoweName="LG2" ShortName="LG2" ShorterName="LG2" BoatName="Lee Gate 2" HullNum="Mark-05" Skipper="" PeliID="125" RadioIP="172.20.2.125">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="126" ShapeID="34" StoweName="WG1" ShortName="WG1" ShorterName="WG1" BoatName="Wind Gate 1" HullNum="Mark-06" Skipper="" PeliID="126" RadioIP="172.20.2.126">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="127" ShapeID="34" StoweName="WG2" ShortName="WG2" ShorterName="WG2" BoatName="Wind Gate 2" HullNum="Mark-07" Skipper="" PeliID="127" RadioIP="172.20.2.127">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="128" ShapeID="34" StoweName="FL1" ShortName="FL1" ShorterName="FL1" BoatName="Finish Line 1" HullNum="Mark-08" Skipper="" PeliID="128" RadioIP="172.20.2.128">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="129" ShapeID="34" StoweName="FL2" ShortName="FL2" ShorterName="FL2" BoatName="Finish Line 2" HullNum="Mark-09" Skipper="" PeliID="129" RadioIP="172.20.2.129">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="130" ShapeID="34" StoweName="SP1" ShortName="SP1" ShorterName="Sp1" BoatName="Spare" HullNum="Mark-10" Skipper="" PeliID="130" RadioIP="172.20.2.130">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Mark" SourceID="131" ShapeID="34" StoweName="M1" ShortName="M1" ShorterName="M1" BoatName="Mark1" HullNum="Mark-01" Skipper="" PeliID="131" RadioIP="172.20.2.131">
|
|
||||||
<GPSposition Z="5.445" Y="1.12" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0.74" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Yacht" SourceID="101" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
<Boat Type="Yacht" SourceID="101" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
|
||||||
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
|
||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||||
@@ -211,24 +167,5 @@
|
|||||||
<MastTop Z="21.496" Y="3.7" X="0"/>
|
<MastTop Z="21.496" Y="3.7" X="0"/>
|
||||||
<FlagPosition Z="0" Y="6.2" X="0"/>
|
<FlagPosition Z="0" Y="6.2" X="0"/>
|
||||||
</Boat>
|
</Boat>
|
||||||
<Boat Type="Marshall" SourceID="109" ShapeID="24" StoweName="CAM" ShortName="CAM" ShorterName="CAM" BoatName="Cambria" HullNum="TV01" Skipper=" " Helmsman=" " PeliID="109" RadioIP="172.20.2.109">
|
|
||||||
<GPSposition Z="0" Y="0" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="0" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Marshall" SourceID="110" ShapeID="18" StoweName="BYS" ShortName="BYSTANDER" ShorterName="BYS" BoatName="BYSTANDER" HullNum="XR09" Skipper="Stan Gibbs" PeliID="110" RadioIP="172.20.2.110">
|
|
||||||
<GPSposition Z="5.334" Y="3.804" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="3.426" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Marshall" SourceID="111" ShapeID="18" StoweName="SHA" ShortName="SHA" ShorterName="SHA" BoatName="SHAMROCK" HullNum="XR01" Skipper="" PeliID="111" RadioIP="172.20.2.111">
|
|
||||||
<GPSposition Z="5.334" Y="3.804" X="0"/>
|
|
||||||
<FlagPosition Z="0" Y="3.426" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Umpire" SourceID="113" ShapeID="18" StoweName="U1" ShortName="U1" ShorterName="U1" BoatName="VIGILENT" HullNum="XR02" Skipper="" PeliID="113" RadioIP="172.20.2.113">
|
|
||||||
<GPSposition Z="5.334" Y="3.804" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Umpire" SourceID="114" ShapeID="18" StoweName="U2" ShortName="U2" ShorterName="U2" BoatName="RESOLUTE" HullNum="XR03" Skipper="" PeliID="114" RadioIP="172.20.2.114">
|
|
||||||
<GPSposition Z="5.334" Y="3.804" X="0"/>
|
|
||||||
</Boat>
|
|
||||||
<Boat Type="Helicopter" SourceID="140" ShapeID="14" StoweName="HL1" ShortName="HEL1" ShorterName="HL1" BoatName="HELICOPTER" PeliID="140" RadioIP="172.20.2.140"/>
|
|
||||||
</Boats>
|
</Boats>
|
||||||
</BoatConfig>
|
</BoatConfig>
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package seng302.server;
|
package seng302.server;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import seng302.server.messages.Header;
|
import seng302.server.messages.*;
|
||||||
import seng302.server.messages.MessageType;
|
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
@@ -23,4 +22,5 @@ public class TestHeader {
|
|||||||
Header h = new Header(MessageType.DISPLAY_TEXT_MESSAGE, 1, (short) 1);
|
Header h = new Header(MessageType.DISPLAY_TEXT_MESSAGE, 1, (short) 1);
|
||||||
assertTrue(h.getSize() == 15); // Spec specifies 15 bytes
|
assertTrue(h.getSize() == 15); // Spec specifies 15 bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,24 +17,6 @@ public class TestMessage {
|
|||||||
private static int BOAT_SUB_MESSAGE_LEN = 20;
|
private static int BOAT_SUB_MESSAGE_LEN = 20;
|
||||||
private static int CRC_LEN = 4;
|
private static int CRC_LEN = 4;
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generated output is the same as the expected output
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testHeatBetBufferOutputLength(){
|
|
||||||
Message m = new Heartbeat(1);
|
|
||||||
List<Integer> output = new ArrayList<>();
|
|
||||||
|
|
||||||
DataOutputStream ds = new DataOutputStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
output.add(b);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m.send(ds);
|
|
||||||
assertTrue(output.size() == (m.getSize() + CRC_LEN + Header.getSize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test output expected is the same as the spec
|
* Test output expected is the same as the spec
|
||||||
@@ -45,92 +27,5 @@ public class TestMessage {
|
|||||||
assertTrue(m.getSize() == (XML_MESSAGE_LEN + "12345".length()));
|
assertTrue(m.getSize() == (XML_MESSAGE_LEN + "12345".length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that when no boats are in the race, that only the base message is sent
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testRaceStatusMessageBufferLenNoBoats(){
|
|
||||||
Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1,
|
|
||||||
0,RaceType.MATCH_RACE,1, new ArrayList<BoatSubMessage>());
|
|
||||||
|
|
||||||
List<Integer> output = new ArrayList<>();
|
|
||||||
|
|
||||||
DataOutputStream ds = new DataOutputStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
output.add(b);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m.send(ds);
|
|
||||||
assertTrue(output.size() == RACE_STATUS_BASE_LEN + Header.getSize() + CRC_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that each boat status is added to the message
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testRaceStatusMessageBufferLenWithBoats(){
|
|
||||||
List<BoatSubMessage> boatMessages = new ArrayList<>();
|
|
||||||
List<Integer> output = new ArrayList<>();
|
|
||||||
|
|
||||||
BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
boatMessages.add(boat1);
|
|
||||||
boatMessages.add(boat2);
|
|
||||||
boatMessages.add(boat3);
|
|
||||||
|
|
||||||
Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1,
|
|
||||||
3,RaceType.MATCH_RACE,1, boatMessages);
|
|
||||||
|
|
||||||
DataOutputStream ds = new DataOutputStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
output.add(b);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m.send(ds);
|
|
||||||
assertTrue(output.size() == (RACE_STATUS_BASE_LEN + (BOAT_SUB_MESSAGE_LEN * 3) + CRC_LEN + Header.getSize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IllegalArgumentException should be thrown when numBoatsInRace is smaller
|
|
||||||
* than the number of boats actually in the race
|
|
||||||
*/
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
|
||||||
public void testRaceStatusTooManyBoats(){
|
|
||||||
List<BoatSubMessage> boatMessages = new ArrayList<>();
|
|
||||||
List<Integer> output = new ArrayList<>();
|
|
||||||
|
|
||||||
BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0,
|
|
||||||
10000, 10000);
|
|
||||||
|
|
||||||
boatMessages.add(boat1);
|
|
||||||
boatMessages.add(boat2);
|
|
||||||
boatMessages.add(boat3);
|
|
||||||
|
|
||||||
Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1,
|
|
||||||
1,RaceType.MATCH_RACE,1, boatMessages);
|
|
||||||
|
|
||||||
m.send(new DataOutputStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
System.out.print("");
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user