addresses = ni.getInetAddresses();
+ while(addresses.hasMoreElements()) {
+ InetAddress address = addresses.nextElement();
+ if(address instanceof Inet4Address) { // skip all ipv6
+ ipAddress = address.getHostAddress();
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (ipAddress == null) {
+ System.out.println("[HOST] Cannot obtain local host ip address.");
+ }
+ return ipAddress;
+ }
+}
diff --git a/src/main/java/seng302/gameServer/ServerDescription.java b/src/main/java/seng302/gameServer/ServerDescription.java
new file mode 100644
index 00000000..02440382
--- /dev/null
+++ b/src/main/java/seng302/gameServer/ServerDescription.java
@@ -0,0 +1,73 @@
+package seng302.gameServer;
+
+public class ServerDescription {
+ private String address;
+ private Integer portNum;
+ private String serverName;
+ private String mapName;
+ private Integer spacesLeft;
+
+ public ServerDescription(String serverName, String mapName, Integer spacesLeft, String address, Integer portNum){
+ this.serverName = serverName;
+ this.mapName = mapName;
+ this.spacesLeft = spacesLeft;
+ this.address = address;
+ this.portNum = portNum;
+ }
+
+
+ public String getName() {
+ return serverName;
+ }
+
+ public String getMapName() {
+ return mapName;
+ }
+
+ public Integer portNumber() {
+ return portNum;
+ }
+
+ public String getAddress(){
+ return address;
+ }
+
+ public Integer spacesLeft() {
+ return spacesLeft;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!ServerDescription.class.isAssignableFrom(obj.getClass())) {
+ return false;
+ }
+ final ServerDescription other = (ServerDescription) obj;
+
+ if (!this.getAddress().equals(other.getAddress()) ) {
+ return false;
+ }
+
+ if (!this.portNumber().equals(other.portNumber())){
+ return false;
+ }
+
+ if (!this.getMapName().equals(other.getMapName())){
+ return false;
+ }
+
+ if (!this.getName().equals(other.getName())){
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getName().hashCode() + this.getAddress().hashCode() +
+ this.portNumber().hashCode() + this.getMapName().hashCode();
+ }
+}
diff --git a/src/main/java/seng302/gameServer/ServerToClientThread.java b/src/main/java/seng302/gameServer/ServerToClientThread.java
index 3a9b4057..82e481ce 100644
--- a/src/main/java/seng302/gameServer/ServerToClientThread.java
+++ b/src/main/java/seng302/gameServer/ServerToClientThread.java
@@ -1,59 +1,24 @@
package seng302.gameServer;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import seng302.gameServer.messages.*;
+import seng302.model.Player;
+import seng302.model.ServerYacht;
+import seng302.model.stream.packets.PacketType;
+import seng302.model.stream.packets.StreamPacket;
+import seng302.model.stream.xml.generator.Race;
+import seng302.utilities.XMLGenerator;
+
+import java.io.*;
import java.net.Socket;
import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
+import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import seng302.gameServer.messages.BoatAction;
-import seng302.gameServer.messages.BoatLocationMessage;
-import seng302.gameServer.messages.ClientType;
-import seng302.gameServer.messages.CustomizeRequestType;
-import seng302.gameServer.messages.Message;
-import seng302.gameServer.messages.RegistrationResponseMessage;
-import seng302.gameServer.messages.RegistrationResponseStatus;
-import seng302.gameServer.messages.XMLMessage;
-import seng302.gameServer.messages.XMLMessageSubType;
-import seng302.gameServer.messages.YachtEventCodeMessage;
-import seng302.gameServer.messages.YachtEventCodeMessage;
-import seng302.model.Player;
-import seng302.model.ServerYacht;
-import seng302.model.stream.packets.PacketType;
-import seng302.model.stream.packets.StreamPacket;
-import seng302.model.stream.xml.generator.Race;
-import seng302.model.stream.xml.generator.Regatta;
-import seng302.utilities.XMLGenerator;
-import seng302.gameServer.messages.BoatAction;
-import seng302.gameServer.messages.BoatLocationMessage;
-import seng302.gameServer.messages.ClientType;
-import seng302.gameServer.messages.Message;
-import seng302.gameServer.messages.RegistrationResponseMessage;
-import seng302.gameServer.messages.RegistrationResponseStatus;
-import seng302.gameServer.messages.XMLMessage;
-import seng302.gameServer.messages.XMLMessageSubType;
-import seng302.gameServer.messages.YachtEventCodeMessage;
-import seng302.model.Player;
-import seng302.model.ServerYacht;
-import seng302.model.stream.packets.PacketType;
-import seng302.model.stream.packets.StreamPacket;
-import seng302.model.stream.xml.generator.Race;
-import seng302.model.stream.xml.generator.Regatta;
-import seng302.utilities.XMLGenerator;
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
@@ -258,12 +223,6 @@ public class ServerToClientThread implements Runnable, Observer {
race.addBoat(yacht);
}
- //@TODO calculate lat/lng values
- xml.setRegatta(
- new Regatta(
- "Party Parrot Test Server", "Bermuda Test Course",
- 57.6679590, 11.8503233)
- );
xml.setRace(race);
XMLMessage xmlMessage;
diff --git a/src/main/java/seng302/gameServer/messages/MarkRoundingMessage.java b/src/main/java/seng302/gameServer/messages/MarkRoundingMessage.java
index c32a6927..b1276814 100644
--- a/src/main/java/seng302/gameServer/messages/MarkRoundingMessage.java
+++ b/src/main/java/seng302/gameServer/messages/MarkRoundingMessage.java
@@ -22,6 +22,7 @@ public class MarkRoundingMessage extends Message{
* @param roundingBoatStatus roundingBoatStatus
* @param roundingSide roundingSide
* @param markId markId
+ * @param markType .
*/
public MarkRoundingMessage(int ackNumber, int raceId, int sourceId, RoundingBoatStatus roundingBoatStatus,
RoundingSide roundingSide, MarkType markType, int markId) {
diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java
index 64143023..859db93c 100644
--- a/src/main/java/seng302/model/ServerYacht.java
+++ b/src/main/java/seng302/model/ServerYacht.java
@@ -1,8 +1,5 @@
package seng302.model;
-import java.util.HashMap;
-import java.util.Observable;
-import java.util.Observer;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,6 +8,10 @@ import seng302.gameServer.messages.BoatStatus;
import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+
/**
* Yacht class for the racing boat. Class created to store more variables (eg. boat statuses)
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
@@ -123,6 +124,7 @@ public class ServerYacht extends Observable {
/**
* Swaps the boats direction from one side of the wind to the other.
+ * @param windDirection .
*/
public void tackGybe(Double windDirection) {
if (isAuto) {
diff --git a/src/main/java/seng302/utilities/XMLGenerator.java b/src/main/java/seng302/utilities/XMLGenerator.java
index 7fcc8efd..6c478af2 100644
--- a/src/main/java/seng302/utilities/XMLGenerator.java
+++ b/src/main/java/seng302/utilities/XMLGenerator.java
@@ -3,13 +3,15 @@ package seng302.utilities;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
+import seng302.gameServer.messages.XMLMessageSubType;
+import seng302.model.stream.xml.generator.Race;
+import seng302.model.stream.xml.generator.Regatta;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
-import seng302.model.stream.xml.generator.Race;
-import seng302.model.stream.xml.generator.Regatta;
-import seng302.gameServer.messages.XMLMessageSubType;
+import java.util.Random;
/**
* An XML generator to generate the Race, Boat, and Regatta XML dynamically
@@ -20,9 +22,14 @@ public class XMLGenerator {
private static final String BOATS_TEMPLATE_NAME = "boats.ftlh";
private static final String RACE_TEMPLATE_NAME = "race.ftlh";
private Configuration configuration;
- private Regatta regatta;
+ private Regatta regatta = null;
private Race race;
+ public static Regatta DEFAULT_REGATTA = new Regatta("Party Parrot Test Server " + new Random().nextInt(100),
+ "Bermuda Test Course",
+ 57.6679590,
+ 11.8503233);
+
/**
* Set up a configuration instance for Apache Freemake
*/
@@ -106,7 +113,7 @@ public class XMLGenerator {
public String getRegattaAsXml(){
String result = null;
- if (regatta == null) return null;
+ if (regatta == null) regatta = DEFAULT_REGATTA;
try {
result = parseToXmlString(REGATTA_TEMPLATE_NAME, XMLMessageSubType.REGATTA);
diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java
index 443342de..8c6b7274 100644
--- a/src/main/java/seng302/visualiser/GameClient.java
+++ b/src/main/java/seng302/visualiser/GameClient.java
@@ -142,6 +142,7 @@ public class GameClient {
}
private void loadStartScreen() {
+
socketThread.setSocketToClose();
if (server != null) {
server.terminate();
diff --git a/src/main/java/seng302/visualiser/ServerListener.java b/src/main/java/seng302/visualiser/ServerListener.java
new file mode 100644
index 00000000..34b76fdb
--- /dev/null
+++ b/src/main/java/seng302/visualiser/ServerListener.java
@@ -0,0 +1,113 @@
+package seng302.visualiser;
+
+import seng302.gameServer.ServerAdvertiser;
+import seng302.gameServer.ServerDescription;
+
+import javax.jmdns.JmDNS;
+import javax.jmdns.ServiceEvent;
+import javax.jmdns.ServiceListener;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import static seng302.gameServer.ServerAdvertiser.getLocalHostIp;
+
+/**
+ * Listens for servers on the local network
+ */
+public class ServerListener{
+ private static ServerListener instance;
+ private ServerListenerDelegate delegate;
+ private JmDNS jmdns = null;
+ GameServeMonitor listener;
+
+ private class GameServeMonitor implements ServiceListener {
+ private Set servers;
+
+ GameServeMonitor(){
+ servers = new HashSet<>();
+ }
+
+ /**
+ * A Service has been detected but not resolved
+ * @param event The ServiceEvent
+ */
+ @Override
+ public void serviceAdded(ServiceEvent event) {
+ }
+
+ /**
+ * A Service has been removed / unregistered
+ * @param event The ServiceEvent
+ */
+ @Override
+ public void serviceRemoved(ServiceEvent event) {
+ String serverName = event.getInfo().getName();
+
+ ServerDescription toRemove = null;
+
+ for (ServerDescription server : servers){
+ if (server.getName().equals(serverName)){
+ toRemove = server;
+ }
+ }
+
+ if (toRemove != null){
+ servers.remove(toRemove);
+ }
+
+ delegate.serverRemoved(new ArrayList(servers));
+
+ // Get all other servers with the same name to respond if they are up
+ jmdns.requestServiceInfo(ServerAdvertiser.SERVICE_TYPE, serverName);
+
+ }
+
+ /**
+ * A Service has been added and resolved
+ * @param event The ServiceEvent
+ */
+ @Override
+ public void serviceResolved(ServiceEvent event) {
+ String address = event.getInfo().getServer();
+ Integer portNum = event.getInfo().getPort();
+
+ String serverName = event.getInfo().getName();
+ String mapName = event.getInfo().getPropertyString("map");
+ Integer spacesLeft = Integer.parseInt(event.getInfo().getPropertyString("spacesLeft"));
+
+ ServerDescription serverDescription = new ServerDescription(serverName, mapName, spacesLeft, address, portNum);
+
+ servers.remove(serverDescription);
+ servers.add(serverDescription);
+
+ delegate.serverDetected(serverDescription, new ArrayList(servers));
+ }
+ }
+
+ private ServerListener() throws IOException {
+ jmdns = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
+ listener = new GameServeMonitor();
+ jmdns.addServiceListener(ServerAdvertiser.SERVICE_TYPE, listener);
+ }
+
+ public static ServerListener getInstance() throws IOException {
+ if (instance == null){
+ instance = new ServerListener();
+ }
+
+ return instance;
+ }
+
+ /**
+ * Set the delegate to handle events
+ * @param delegate .
+ */
+ public void setDelegate(ServerListenerDelegate delegate){
+ this.delegate = delegate;
+ }
+
+
+}
diff --git a/src/main/java/seng302/visualiser/ServerListenerDelegate.java b/src/main/java/seng302/visualiser/ServerListenerDelegate.java
new file mode 100644
index 00000000..15400a86
--- /dev/null
+++ b/src/main/java/seng302/visualiser/ServerListenerDelegate.java
@@ -0,0 +1,10 @@
+package seng302.visualiser;
+
+import seng302.gameServer.ServerDescription;
+
+import java.util.List;
+
+public interface ServerListenerDelegate {
+ void serverRemoved(List currentServers);
+ void serverDetected(ServerDescription serverDescription, List servers);
+}
diff --git a/src/main/java/seng302/visualiser/controllers/StartScreenController.java b/src/main/java/seng302/visualiser/controllers/StartScreenController.java
index eced061e..af1f4c3c 100644
--- a/src/main/java/seng302/visualiser/controllers/StartScreenController.java
+++ b/src/main/java/seng302/visualiser/controllers/StartScreenController.java
@@ -5,6 +5,7 @@ import com.jfoenix.controls.JFXButton;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
+import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
@@ -14,6 +15,26 @@ import javafx.scene.effect.DropShadow;
import javafx.scene.paint.Color;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Button;
+import javafx.scene.control.ListView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.GridPane;
+import seng302.gameServer.ServerAdvertiser;
+import seng302.gameServer.ServerDescription;
+import seng302.visualiser.GameClient;
+import seng302.visualiser.ServerListener;
+import seng302.visualiser.ServerListenerDelegate;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ResourceBundle;
public class StartScreenController implements Initializable {
@@ -26,6 +47,38 @@ public class StartScreenController implements Initializable {
private Node serverList;
private Logger logger = LoggerFactory.getLogger(StartScreenController.class);
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+// gameClient = new GameClient(holder);
+
+ try {
+ ServerListener.getInstance().setDelegate(this);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ joinLobbyButton.setOnAction(event -> joinLobbyClicked());
+ }
+//
+// /**
+// * Loads the fxml content into the parent pane
+// * @param jfxUrl
+// * @return the controller of the fxml
+// */
+// private Object setContentPane(String jfxUrl) {
+// try {
+// AnchorPane contentPane = (AnchorPane) startScreen2.getParent();
+// contentPane.getChildren().removeAll();
+// contentPane.getChildren().clear();
+// contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString());
+// FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(jfxUrl));
+// contentPane.getChildren().addAll((Pane) fxmlLoader.load());
+//
+// return fxmlLoader.getController();
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// return null;
+// }
private void setInitialDropShadow(){
DropShadow dropShadow = new DropShadow();
diff --git a/src/main/java/seng302/visualiser/fxObjects/BoatObject.java b/src/main/java/seng302/visualiser/fxObjects/BoatObject.java
index a86a3ac8..ccabe35d 100644
--- a/src/main/java/seng302/visualiser/fxObjects/BoatObject.java
+++ b/src/main/java/seng302/visualiser/fxObjects/BoatObject.java
@@ -1,7 +1,5 @@
package seng302.visualiser.fxObjects;
-import java.util.ArrayList;
-import java.util.List;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.Group;
@@ -14,6 +12,9 @@ import javafx.scene.shape.Polyline;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.transform.Rotate;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* BoatGroup is a javafx group that by default contains a graphical objects for representing a 2
* dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path,
@@ -130,6 +131,7 @@ public class BoatObject extends Group {
* @param rotation The rotation by which the boat moves
* @param velocity The velocity the boat is moving
* @param sailIn Boolean to toggle sail state.
+ * @param windDir .
*/
public void moveTo(double x, double y, double rotation, double velocity, Boolean sailIn, double windDir) {
Double dx = Math.abs(boatPoly.getLayoutX() - x);
diff --git a/src/test/java/seng302/gameServer/server/TestServerDesc.java b/src/test/java/seng302/gameServer/server/TestServerDesc.java
new file mode 100644
index 00000000..8ee50255
--- /dev/null
+++ b/src/test/java/seng302/gameServer/server/TestServerDesc.java
@@ -0,0 +1,48 @@
+package seng302.gameServer.server;
+
+import org.junit.Test;
+import seng302.gameServer.ServerDescription;
+
+import static org.junit.Assert.assertTrue;
+
+public class TestServerDesc {
+ @Test
+ public void testEquals(){
+ ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234);
+ ServerDescription two = new ServerDescription("a", "b", 10, "asd", 1234);
+
+ assertTrue(one.equals(two));
+ }
+
+ @Test
+ public void testNotEqualName(){
+ ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234);
+ ServerDescription two = new ServerDescription("a2", "b", 10, "asd", 1234);
+
+ assertTrue(!one.equals(two));
+ }
+
+ @Test
+ public void testNotEqualMap(){
+ ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234);
+ ServerDescription two = new ServerDescription("a", "ba", 10, "asd", 1234);
+
+ assertTrue(!one.equals(two));
+ }
+
+ @Test
+ public void testNotEqualPort(){
+ ServerDescription one = new ServerDescription("a", "b", 10, "asd", 1234);
+ ServerDescription two = new ServerDescription("a", "b", 10, "asd", 12341);
+
+ assertTrue(!one.equals(two));
+ }
+
+ @Test
+ public void testNotEqualAddress(){
+ ServerDescription one = new ServerDescription("a", "b", 10, "as1d", 1234);
+ ServerDescription two = new ServerDescription("a", "b", 10, "asd", 1234);
+
+ assertTrue(!one.equals(two));
+ }
+}