mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Implemented server re-registration when a server closes / updates
- When a server is closed, it will disappear from the server list - When a player joins a server, the number of spaces left will decrease - Servers now disappear instead of duplicating - Added tests for ServerDescription - Added documentation for new classes Tags: #story[1247]
This commit is contained in:
@@ -7,16 +7,10 @@ import javafx.scene.Parent;
|
|||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.*;
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.DefaultParser;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.gameServer.ServerAdvertiser;
|
import seng302.gameServer.ServerAdvertiser;
|
||||||
import seng302.model.PolarTable;
|
|
||||||
import seng302.visualiser.ServerListener;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -87,6 +81,13 @@ public class App extends Application {
|
|||||||
// ClientPacketParser.appClose();
|
// ClientPacketParser.appClose();
|
||||||
// ClientPacketParser.appClose();
|
// ClientPacketParser.appClose();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerAdvertiser.getInstance().unregister();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
logger.warn("Could not un-register game");
|
||||||
|
}
|
||||||
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,22 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 seng302.gameServer.messages.BoatAction;
|
import seng302.gameServer.messages.*;
|
||||||
import seng302.gameServer.messages.BoatStatus;
|
import seng302.model.*;
|
||||||
import seng302.gameServer.messages.CustomizeRequestType;
|
|
||||||
import seng302.gameServer.messages.MarkRoundingMessage;
|
|
||||||
import seng302.gameServer.messages.MarkType;
|
|
||||||
import seng302.gameServer.messages.Message;
|
|
||||||
import seng302.gameServer.messages.RoundingBoatStatus;
|
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
|
||||||
import seng302.model.GeoPoint;
|
|
||||||
import seng302.model.Limit;
|
|
||||||
import seng302.model.Player;
|
|
||||||
import seng302.model.PolarTable;
|
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
import seng302.model.mark.Mark;
|
import seng302.model.mark.Mark;
|
||||||
import seng302.model.mark.MarkOrder;
|
import seng302.model.mark.MarkOrder;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
import seng302.utilities.XMLParser;
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Static class to hold information about the current state of the game (model)
|
* A Static class to hold information about the current state of the game (model)
|
||||||
* Also contains logic for updating itself on regular time intervals on its own thread
|
* Also contains logic for updating itself on regular time intervals on its own thread
|
||||||
@@ -699,4 +684,11 @@ public class GameState implements Runnable {
|
|||||||
public static void resetCustomizationFlag() {
|
public static void resetCustomizationFlag() {
|
||||||
customizationFlag = false;
|
customizationFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Integer getSpacesLeft(){
|
||||||
|
Integer numberOfPlayers = GameState.getPlayers().size();
|
||||||
|
Integer maxPlayers = GameState.MAX_PLAYERS;
|
||||||
|
|
||||||
|
return maxPlayers - numberOfPlayers - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
import seng302.gameServer.messages.*;
|
import seng302.gameServer.messages.*;
|
||||||
import seng302.model.GeoPoint;
|
import seng302.model.GeoPoint;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
import seng302.model.PolarTable;
|
import seng302.model.PolarTable;
|
||||||
import seng302.model.ServerYacht;
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.mark.CompoundMark;
|
import seng302.model.mark.CompoundMark;
|
||||||
|
import seng302.model.stream.xml.parser.RegattaXMLData;
|
||||||
import seng302.utilities.GeoUtility;
|
import seng302.utilities.GeoUtility;
|
||||||
|
import seng302.utilities.XMLGenerator;
|
||||||
|
import seng302.utilities.XMLParser;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -42,6 +51,41 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||||
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
|
private Logger logger = LoggerFactory.getLogger(MainServerThread.class);
|
||||||
|
|
||||||
|
private void startAdvertisingServer(){
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder db;
|
||||||
|
Document doc;
|
||||||
|
XMLGenerator generator = new XMLGenerator();
|
||||||
|
|
||||||
|
try {
|
||||||
|
db = dbf.newDocumentBuilder();
|
||||||
|
String regatta = generator.getRegattaAsXml();
|
||||||
|
StringReader stringReader = new StringReader(regatta);
|
||||||
|
InputSource is = new InputSource(stringReader);
|
||||||
|
doc = db.parse(is);
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
logger.warn("Couldn't load race regatta");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc);
|
||||||
|
|
||||||
|
Integer spacesLeft = GameState.getSpacesLeft();
|
||||||
|
|
||||||
|
// No spaces left on server
|
||||||
|
if (spacesLeft < 1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start advertising server
|
||||||
|
try{
|
||||||
|
ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setSpacesLeft(spacesLeft);
|
||||||
|
ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Could not register server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MainServerThread() {
|
public MainServerThread() {
|
||||||
new GameState("localhost");
|
new GameState("localhost");
|
||||||
try {
|
try {
|
||||||
@@ -50,13 +94,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
|
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start advertising server
|
startAdvertisingServer();
|
||||||
try{
|
|
||||||
ServerAdvertiser.getInstance().registerGame(PORT, "PP Test Server", 10, "Random Map");
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("Could not register server");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
|
||||||
GameState.addMarkPassListener(this::broadcastMessage);
|
GameState.addMarkPassListener(this::broadcastMessage);
|
||||||
@@ -189,6 +227,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Couldn't update advertisement");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +259,13 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ServerAdvertiser.getInstance().setSpacesLeft(GameState.getSpacesLeft());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("Couldn't update advertisement");
|
||||||
|
}
|
||||||
|
|
||||||
closedConnection.terminate();
|
closedConnection.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +273,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().unregister();
|
ServerAdvertiser.getInstance().unregister();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Error unregistering server");
|
logger.warn("Error unregistered server");
|
||||||
}
|
}
|
||||||
|
|
||||||
initialiseBoatPositions();
|
initialiseBoatPositions();
|
||||||
|
|||||||
@@ -6,20 +6,45 @@ import java.io.IOException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advertises the game server on the local network
|
||||||
|
*/
|
||||||
public class ServerAdvertiser {
|
public class ServerAdvertiser {
|
||||||
|
/*
|
||||||
|
Our service name & protocol
|
||||||
|
|
||||||
|
This must be in the format _Service._Proto.Name as per http://www.ietf.org/rfc/rfc2782.txt
|
||||||
|
Where Service is unique on the network, and protocol is usually _tcp.
|
||||||
|
|
||||||
|
The pseudo-domain 'local.' must end in a full-stop. This is used to indicate that
|
||||||
|
the lookup should be performed using an IP multicast query on the local IP network.
|
||||||
|
|
||||||
|
Read this before changing any of the following values
|
||||||
|
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/NetServices/Articles/domainnames.html#//apple_ref/doc/uid/TP40002460-SW1
|
||||||
|
*/
|
||||||
private static String SERVICE = "_partyatsea";
|
private static String SERVICE = "_partyatsea";
|
||||||
private static String PROTOCOL = "_tcp";
|
private static String PROTOCOL = "_tcp";
|
||||||
public static String SERVICE_TYPE = SERVICE + "." + PROTOCOL + ".local.";
|
public static String SERVICE_TYPE = SERVICE + "." + PROTOCOL + ".local.";
|
||||||
private static Integer PROTO_VERSION = 1;
|
|
||||||
|
|
||||||
|
|
||||||
private static ServerAdvertiser instance = null;
|
private static ServerAdvertiser instance = null;
|
||||||
private static JmDNS jmdnsInstance = null;
|
private static JmDNS jmdnsInstance = null;
|
||||||
|
private ServiceInfo serviceInfo; // Note: Whenever this is changed, our service will be re-registered on the network.
|
||||||
|
|
||||||
|
private Hashtable<String ,String> props;
|
||||||
|
|
||||||
private ServerAdvertiser() throws IOException{
|
private ServerAdvertiser() throws IOException{
|
||||||
jmdnsInstance = JmDNS.create(InetAddress.getLocalHost());
|
jmdnsInstance = JmDNS.create(InetAddress.getLocalHost());
|
||||||
|
|
||||||
|
props = new Hashtable<>();
|
||||||
|
props.put("map", "");
|
||||||
|
props.put("spacesLeft", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance of the ServerAdvertiser, create an instance if there isn't already one
|
||||||
|
* @return A ServerAdvertiser Instance
|
||||||
|
* @throws IOException If there was an exception creating the instance
|
||||||
|
*/
|
||||||
public static ServerAdvertiser getInstance() throws IOException {
|
public static ServerAdvertiser getInstance() throws IOException {
|
||||||
if (instance == null){
|
if (instance == null){
|
||||||
instance = new ServerAdvertiser();
|
instance = new ServerAdvertiser();
|
||||||
@@ -28,13 +53,47 @@ public class ServerAdvertiser {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerGame(Integer portNo, String serverName, Integer spacesLeft, String mapName) {
|
/**
|
||||||
Hashtable<String ,String> props = new Hashtable<>();
|
* Set the map name & broadcast an update on the network
|
||||||
|
* @param mapName The new map name
|
||||||
|
* @return The current ServerAdvertiser instance
|
||||||
|
*/
|
||||||
|
public ServerAdvertiser setMapName(String mapName){
|
||||||
|
props.replace("map", mapName);
|
||||||
|
|
||||||
props.put("map", mapName);
|
if (serviceInfo != null){
|
||||||
props.put("spacesLeft", spacesLeft.toString());
|
serviceInfo.setText(props);
|
||||||
|
}
|
||||||
|
|
||||||
ServiceInfo serviceInfo = ServiceInfo.create(SERVICE_TYPE, serverName, portNo, 0, 0, props);
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the spaces left on the server & broadcast an update on the network
|
||||||
|
* @param spacesLeft The number of spaces left on the server
|
||||||
|
* @return The current ServerAdvertiser instance
|
||||||
|
*/
|
||||||
|
public ServerAdvertiser setSpacesLeft(Integer spacesLeft){
|
||||||
|
props.replace("spacesLeft", spacesLeft.toString());
|
||||||
|
|
||||||
|
if (serviceInfo != null){
|
||||||
|
serviceInfo.setText(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register this service on the network
|
||||||
|
*
|
||||||
|
* Note: other parameters (map name/spaces left etc) are set after the
|
||||||
|
* service has been registered
|
||||||
|
* @param portNo The servers port number
|
||||||
|
* @param serverName The servers name
|
||||||
|
*/
|
||||||
|
public void registerGame(Integer portNo, String serverName) {
|
||||||
|
|
||||||
|
serviceInfo = ServiceInfo.create(SERVICE_TYPE, serverName, portNo, 0, 0, props);
|
||||||
|
|
||||||
new java.util.Timer().schedule(
|
new java.util.Timer().schedule(
|
||||||
new java.util.TimerTask() {
|
new java.util.TimerTask() {
|
||||||
@@ -46,12 +105,14 @@ public class ServerAdvertiser {
|
|||||||
System.out.println("Failed");
|
System.out.println("Failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0
|
}, 0);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister the service
|
||||||
|
*/
|
||||||
public void unregister(){
|
public void unregister(){
|
||||||
jmdnsInstance.unregisterAllServices();
|
if (serviceInfo != null)
|
||||||
jmdnsInstance = null;
|
jmdnsInstance.unregisterService(serviceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package seng302.gameServer;
|
|||||||
public class ServerDescription {
|
public class ServerDescription {
|
||||||
private String address;
|
private String address;
|
||||||
private Integer portNum;
|
private Integer portNum;
|
||||||
|
|
||||||
private String serverName;
|
private String serverName;
|
||||||
private String mapName;
|
private String mapName;
|
||||||
private Integer spacesLeft;
|
private Integer spacesLeft;
|
||||||
@@ -36,4 +35,39 @@ public class ServerDescription {
|
|||||||
public Integer spacesLeft() {
|
public Integer spacesLeft() {
|
||||||
return 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,24 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import org.slf4j.Logger;
|
||||||
import java.io.ByteArrayOutputStream;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.io.IOException;
|
import seng302.gameServer.messages.*;
|
||||||
import java.io.InputStream;
|
import seng302.model.Player;
|
||||||
import java.io.InputStreamReader;
|
import seng302.model.ServerYacht;
|
||||||
import java.io.OutputStream;
|
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.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Observable;
|
|
||||||
import java.util.Observer;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.Checksum;
|
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
|
* 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);
|
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);
|
xml.setRace(race);
|
||||||
|
|
||||||
XMLMessage xmlMessage;
|
XMLMessage xmlMessage;
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ package seng302.utilities;
|
|||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
import freemarker.template.TemplateException;
|
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.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import seng302.model.stream.xml.generator.Race;
|
import java.util.Random;
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
|
||||||
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
|
||||||
@@ -20,9 +22,14 @@ public class XMLGenerator {
|
|||||||
private static final String BOATS_TEMPLATE_NAME = "boats.ftlh";
|
private static final String BOATS_TEMPLATE_NAME = "boats.ftlh";
|
||||||
private static final String RACE_TEMPLATE_NAME = "race.ftlh";
|
private static final String RACE_TEMPLATE_NAME = "race.ftlh";
|
||||||
private Configuration configuration;
|
private Configuration configuration;
|
||||||
private Regatta regatta;
|
private Regatta regatta = null;
|
||||||
private Race race;
|
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
|
* Set up a configuration instance for Apache Freemake
|
||||||
*/
|
*/
|
||||||
@@ -106,7 +113,7 @@ public class XMLGenerator {
|
|||||||
public String getRegattaAsXml(){
|
public String getRegattaAsXml(){
|
||||||
String result = null;
|
String result = null;
|
||||||
|
|
||||||
if (regatta == null) return null;
|
if (regatta == null) regatta = DEFAULT_REGATTA;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = parseToXmlString(REGATTA_TEMPLATE_NAME, XMLMessageSubType.REGATTA);
|
result = parseToXmlString(REGATTA_TEMPLATE_NAME, XMLMessageSubType.REGATTA);
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import javax.jmdns.ServiceEvent;
|
|||||||
import javax.jmdns.ServiceListener;
|
import javax.jmdns.ServiceListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.HashSet;
|
||||||
import java.util.Collections;
|
import java.util.Set;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listens for servers on the local network
|
||||||
|
*/
|
||||||
public class ServerListener{
|
public class ServerListener{
|
||||||
private static ServerListener instance;
|
private static ServerListener instance;
|
||||||
private ServerListenerDelegate delegate;
|
private ServerListenerDelegate delegate;
|
||||||
@@ -21,35 +22,51 @@ public class ServerListener{
|
|||||||
GameServeMonitor listener;
|
GameServeMonitor listener;
|
||||||
|
|
||||||
private class GameServeMonitor implements ServiceListener {
|
private class GameServeMonitor implements ServiceListener {
|
||||||
private List<ServerDescription> servers;
|
private Set<ServerDescription> servers;
|
||||||
|
|
||||||
GameServeMonitor(){
|
GameServeMonitor(){
|
||||||
servers = new ArrayList<>();
|
servers = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Service has been detected but not resolved
|
||||||
|
* @param event The ServiceEvent
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void serviceAdded(ServiceEvent event) {
|
public void serviceAdded(ServiceEvent event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Service has been removed / unregistered
|
||||||
|
* @param event The ServiceEvent
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void serviceRemoved(ServiceEvent event) {
|
public void serviceRemoved(ServiceEvent event) {
|
||||||
Integer serverId = -1;
|
String serverName = event.getInfo().getName();
|
||||||
|
|
||||||
for (int i = 0; i < servers.size(); i++){
|
ServerDescription toRemove = null;
|
||||||
ServerDescription server = servers.get(i);
|
|
||||||
if (server.getName().equals(event.getInfo().getName())){
|
for (ServerDescription server : servers){
|
||||||
serverId = i;
|
if (server.getName().equals(serverName)){
|
||||||
break;
|
toRemove = server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverId > 0){
|
if (toRemove != null){
|
||||||
servers.remove(serverId);
|
servers.remove(toRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate.serverRemoved(servers);
|
delegate.serverRemoved(new ArrayList<ServerDescription>(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
|
@Override
|
||||||
public void serviceResolved(ServiceEvent event) {
|
public void serviceResolved(ServiceEvent event) {
|
||||||
String address = event.getInfo().getServer();
|
String address = event.getInfo().getServer();
|
||||||
@@ -60,9 +77,11 @@ public class ServerListener{
|
|||||||
Integer spacesLeft = Integer.parseInt(event.getInfo().getPropertyString("spacesLeft"));
|
Integer spacesLeft = Integer.parseInt(event.getInfo().getPropertyString("spacesLeft"));
|
||||||
|
|
||||||
ServerDescription serverDescription = new ServerDescription(serverName, mapName, spacesLeft, address, portNum);
|
ServerDescription serverDescription = new ServerDescription(serverName, mapName, spacesLeft, address, portNum);
|
||||||
|
|
||||||
|
servers.remove(serverDescription);
|
||||||
servers.add(serverDescription);
|
servers.add(serverDescription);
|
||||||
|
|
||||||
delegate.serverDetected(serverDescription, Collections.unmodifiableList(servers));
|
delegate.serverDetected(serverDescription, new ArrayList<ServerDescription>(servers));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +99,10 @@ public class ServerListener{
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the delegate to handle events
|
||||||
|
* @param delegate .
|
||||||
|
*/
|
||||||
public void setDelegate(ServerListenerDelegate delegate){
|
public void setDelegate(ServerListenerDelegate delegate){
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
package seng302.visualiser.controllers;
|
package seng302.visualiser.controllers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import javafx.application.Platform;
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import com.sun.security.ntlm.Server;
|
|
||||||
import cucumber.api.java.en.But;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
@@ -17,12 +9,20 @@ import javafx.scene.control.ListView;
|
|||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import seng302.gameServer.GameState;
|
|
||||||
import seng302.gameServer.ServerDescription;
|
import seng302.gameServer.ServerDescription;
|
||||||
import seng302.visualiser.GameClient;
|
import seng302.visualiser.GameClient;
|
||||||
import seng302.visualiser.ServerListener;
|
import seng302.visualiser.ServerListener;
|
||||||
import seng302.visualiser.ServerListenerDelegate;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class describing the actions of the start screen controller
|
* A Class describing the actions of the start screen controller
|
||||||
* Created by wmu16 on 10/07/17.
|
* Created by wmu16 on 10/07/17.
|
||||||
@@ -192,6 +192,10 @@ public class StartScreenController implements Initializable, ServerListenerDeleg
|
|||||||
return ipAddress;
|
return ipAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the server list with new information
|
||||||
|
* @param servers The current list of servers
|
||||||
|
*/
|
||||||
private void refreshServerList(List<ServerDescription> servers){
|
private void refreshServerList(List<ServerDescription> servers){
|
||||||
this.serverList.getItems().clear();
|
this.serverList.getItems().clear();
|
||||||
|
|
||||||
@@ -204,20 +208,20 @@ public class StartScreenController implements Initializable, ServerListenerDeleg
|
|||||||
public void serverRemoved(List<ServerDescription> currentServers) {
|
public void serverRemoved(List<ServerDescription> currentServers) {
|
||||||
this.servers = currentServers;
|
this.servers = currentServers;
|
||||||
|
|
||||||
refreshServerList(currentServers);
|
Platform.runLater(() -> refreshServerList(currentServers));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
|
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
|
|
||||||
refreshServerList(servers);
|
Platform.runLater(() -> refreshServerList(servers));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void joinLobbyClicked() {
|
private void joinLobbyClicked() {
|
||||||
Integer selectedServer = serverList.getSelectionModel().getSelectedIndex();
|
Integer selectedServer = serverList.getSelectionModel().getSelectedIndex();
|
||||||
|
|
||||||
if (this.servers == null || selectedServer >= this.servers.size()){
|
if (this.servers == null || selectedServer >= this.servers.size() || selectedServer < 0){
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR, "Invalid server selected");
|
Alert alert = new Alert(Alert.AlertType.ERROR, "Invalid server selected");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user