mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 14:28:43 +00:00
Various bug fixes
- Fixed bug where an invalid port number would crash the program - Closed the stage before cleaning up resources. This speeds up closing the app. - Added error handling for when the client looses connection to the server. Tags: #story[1281]
This commit is contained in:
@@ -77,9 +77,9 @@ public class MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void updateBoats(List<ServerYacht> yachts) {
|
public static void updateBoats(List<ServerYacht> yachts) {
|
||||||
for (ServerYacht serverYacht : yachts) {
|
// for (ServerYacht serverYacht : yachts) {
|
||||||
System.out.println(serverYacht);
|
// System.out.println(serverYacht);
|
||||||
}
|
// }
|
||||||
xmlGenerator.getRace().setBoats(yachts);
|
xmlGenerator.getRace().setBoats(yachts);
|
||||||
String xmlStr = xmlGenerator.getBoatsAsXml();
|
String xmlStr = xmlGenerator.getBoatsAsXml();
|
||||||
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package seng302.gameServer;
|
package seng302.gameServer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import seng302.discoveryServer.DiscoveryServerClient;
|
import seng302.discoveryServer.DiscoveryServerClient;
|
||||||
import seng302.discoveryServer.util.ServerListing;
|
import seng302.discoveryServer.util.ServerListing;
|
||||||
|
|
||||||
@@ -38,6 +40,7 @@ public class ServerAdvertiser {
|
|||||||
private DiscoveryServerClient repositoryClient;
|
private DiscoveryServerClient repositoryClient;
|
||||||
|
|
||||||
private Hashtable<String ,String> props;
|
private Hashtable<String ,String> props;
|
||||||
|
private Logger logger = LoggerFactory.getLogger(ServerAdvertiser.class);
|
||||||
|
|
||||||
private ServerAdvertiser() throws IOException{
|
private ServerAdvertiser() throws IOException{
|
||||||
jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
|
jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
|
||||||
@@ -128,7 +131,7 @@ public class ServerAdvertiser {
|
|||||||
try {
|
try {
|
||||||
jmdnsInstance.registerService(serviceInfo);
|
jmdnsInstance.registerService(serviceInfo);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Failed");
|
logger.warn("Failed to register service info");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ public class StreamParser {
|
|||||||
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
|
||||||
String xmlMessage = new String(
|
String xmlMessage = new String(
|
||||||
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
|
||||||
System.out.println(xmlMessage);
|
|
||||||
//Create XML document Object
|
//Create XML document Object
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -380,7 +381,7 @@ public class XMLParser {
|
|||||||
/**
|
/**
|
||||||
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
* This ungodly combination of existing methods and code blocks parses a race definition file.
|
||||||
* Look upon it and despair.
|
* Look upon it and despair.
|
||||||
* @param url the location of the race def file
|
* @param url The input file path
|
||||||
* @param serverName the name of the server
|
* @param serverName the name of the server
|
||||||
* @param repetitions the repetitions of a segment of the race def file.
|
* @param repetitions the repetitions of a segment of the race def file.
|
||||||
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
|
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
|
||||||
@@ -388,14 +389,14 @@ public class XMLParser {
|
|||||||
* @return a pair which contains regatta string, race string as key, value pair.
|
* @return a pair which contains regatta string, race string as key, value pair.
|
||||||
*/
|
*/
|
||||||
public static Pair<RegattaXMLTemplate, RaceXMLTemplate> parseRaceDef(
|
public static Pair<RegattaXMLTemplate, RaceXMLTemplate> parseRaceDef(
|
||||||
String url, String serverName, Integer repetitions, Integer maxPlayers, Boolean tokensEnabled
|
String url, String serverName, Integer repetitions, Integer maxPlayers, Boolean tokensEnabled
|
||||||
) {
|
) {
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
db = dbf.newDocumentBuilder();
|
db = dbf.newDocumentBuilder();
|
||||||
doc = db.parse(url);
|
doc = db.parse(XMLParser.class.getResourceAsStream(url));
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ public class ClientToServerThread implements Runnable {
|
|||||||
void notifyDisconnection(String message);
|
void notifyDisconnection(String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ConnectionErrorListener {
|
||||||
|
void notifyConnectionError(String message);
|
||||||
|
}
|
||||||
|
|
||||||
private class ByteReadException extends Exception {
|
private class ByteReadException extends Exception {
|
||||||
private ByteReadException(String message) {
|
private ByteReadException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
@@ -66,6 +71,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
|
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
|
||||||
private List<ClientSocketListener> listeners = new ArrayList<>();
|
private List<ClientSocketListener> listeners = new ArrayList<>();
|
||||||
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
|
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
|
||||||
|
private ConnectionErrorListener connectionErrorListener = null;
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
|
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
@@ -183,6 +189,18 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleConnectionError(String message){
|
||||||
|
if (connectionErrorListener != null){
|
||||||
|
connectionErrorListener.notifyConnectionError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Couldn't close socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a request to the server asking for a source ID
|
* Sends a request to the server asking for a source ID
|
||||||
*/
|
*/
|
||||||
@@ -212,6 +230,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
logger.error("Server Denied Connection, Exiting");
|
logger.error("Server Denied Connection, Exiting");
|
||||||
|
|
||||||
final String alertErrorText;
|
final String alertErrorText;
|
||||||
@@ -222,6 +241,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
else{
|
else{
|
||||||
alertErrorText = "Could not connect to server";
|
alertErrorText = "Could not connect to server";
|
||||||
}
|
}
|
||||||
|
handleConnectionError("Server no longer available.");
|
||||||
notifyDisconnectListeners(alertErrorText);
|
notifyDisconnectListeners(alertErrorText);
|
||||||
closeSocket();
|
closeSocket();
|
||||||
}
|
}
|
||||||
@@ -351,6 +371,12 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setConnectionErrorListener(ConnectionErrorListener listener){
|
||||||
|
synchronized (this){
|
||||||
|
connectionErrorListener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int readByte() throws ByteReadException {
|
private int readByte() throws ByteReadException {
|
||||||
int currentByte = -1;
|
int currentByte = -1;
|
||||||
try {
|
try {
|
||||||
@@ -365,6 +391,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
notifyDisconnectListeners("Cannot read from server.");
|
notifyDisconnectListeners("Cannot read from server.");
|
||||||
closeSocket();
|
closeSocket();
|
||||||
logger.warn("InputStream reach end of stream", 1);
|
logger.warn("InputStream reach end of stream", 1);
|
||||||
|
handleConnectionError("Could not connect to server. Server is no longer available.");
|
||||||
}
|
}
|
||||||
return currentByte;
|
return currentByte;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,13 +119,23 @@ public class GameClient {
|
|||||||
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
|
||||||
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
|
||||||
|
|
||||||
|
getServerThread().setConnectionErrorListener((eMessage) -> {
|
||||||
|
ViewManager.getInstance().showErrorSnackBar(eMessage);
|
||||||
|
destroyClientToServerThread();
|
||||||
|
});
|
||||||
|
|
||||||
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
this.lobbyController = ViewManager.getInstance().goToLobby(true);
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
ViewManager.getInstance().showErrorSnackBar("Unable to find server");
|
ViewManager.getInstance().showErrorSnackBar("There are no servers currently available.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void destroyClientToServerThread() {
|
||||||
|
socketThread.closeSocket();
|
||||||
|
socketThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a game as the host at the given address and starts the visualiser.
|
* Connect to a game as the host at the given address and starts the visualiser.
|
||||||
* @param ipAddress IP to connect to.
|
* @param ipAddress IP to connect to.
|
||||||
@@ -224,7 +234,6 @@ public class GameClient {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RACE_XML:
|
case RACE_XML:
|
||||||
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
|
|
||||||
RaceXMLData raceXMLData = XMLParser.parseRace(
|
RaceXMLData raceXMLData = XMLParser.parseRace(
|
||||||
StreamParser.extractXmlMessage(packet)
|
StreamParser.extractXmlMessage(packet)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
@@ -34,6 +35,8 @@ public class MapMaker {
|
|||||||
private int index = 0;
|
private int index = 0;
|
||||||
private XMLGenerator xmlGenerator = new XMLGenerator();
|
private XMLGenerator xmlGenerator = new XMLGenerator();
|
||||||
|
|
||||||
|
private List<String> maps = new ArrayList<>(Arrays.asList("default.xml", "horseshoe.xml"));
|
||||||
|
|
||||||
public static MapMaker getInstance() {
|
public static MapMaker getInstance() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new MapMaker();
|
instance = new MapMaker();
|
||||||
@@ -42,46 +45,49 @@ public class MapMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MapMaker() {
|
private MapMaker() {
|
||||||
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
|
for (String mapPath : maps){
|
||||||
File[] directoryListing = dir.listFiles();
|
String path = ("/maps/" + mapPath);
|
||||||
if (directoryListing != null) {
|
|
||||||
for (File child : directoryListing) {
|
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
||||||
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
|
path, "", 1, null, false
|
||||||
child.getAbsolutePath(), "", 1, null, false
|
);
|
||||||
);
|
|
||||||
filePaths.add(child.getAbsolutePath());
|
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
|
||||||
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
|
|
||||||
regattas.add(new RegattaXMLData(
|
filePaths.add(path);
|
||||||
|
|
||||||
|
regattas.add(new RegattaXMLData(
|
||||||
regattaTemplate.getRegattaId(),
|
regattaTemplate.getRegattaId(),
|
||||||
regattaTemplate.getName(),
|
regattaTemplate.getName(),
|
||||||
regattaTemplate.getCourseName(),
|
regattaTemplate.getCourseName(),
|
||||||
regattaTemplate.getLatitude(),
|
regattaTemplate.getLatitude(),
|
||||||
regattaTemplate.getLongitude(),
|
regattaTemplate.getLongitude(),
|
||||||
regattaTemplate.getUtcOffset()
|
regattaTemplate.getUtcOffset()
|
||||||
));
|
));
|
||||||
|
|
||||||
RaceXMLTemplate raceTemplate = regattaRace.getValue();
|
RaceXMLTemplate raceTemplate = regattaRace.getValue();
|
||||||
xmlGenerator.setRaceTemplate(raceTemplate);
|
xmlGenerator.setRaceTemplate(raceTemplate);
|
||||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder db;
|
DocumentBuilder db;
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
db = dbf.newDocumentBuilder();
|
db = dbf.newDocumentBuilder();
|
||||||
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
|
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
|
||||||
} catch (ParserConfigurationException | IOException | SAXException e) {
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
RaceXMLData race = XMLParser.parseRace(doc);
|
RaceXMLData race = XMLParser.parseRace(doc);
|
||||||
maxPlayers.add(XMLParser.getMaxPlayers(doc));
|
maxPlayers.add(XMLParser.getMaxPlayers(doc));
|
||||||
|
|
||||||
mapPreviews.add(new MapPreview(
|
mapPreviews.add(new MapPreview(
|
||||||
new ArrayList<>(race.getCompoundMarks().values()),
|
new ArrayList<>(race.getCompoundMarks().values()),
|
||||||
race.getMarkSequence(), race.getCourseLimit()
|
race.getMarkSequence(), race.getCourseLimit()
|
||||||
));
|
));
|
||||||
races.add(race);
|
|
||||||
}
|
races.add(race);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
|
|||||||
@@ -272,6 +272,8 @@ public class ViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void closeAll() {
|
private void closeAll() {
|
||||||
|
if (stage!= null) stage.close();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ServerAdvertiser.getInstance().unregister();
|
ServerAdvertiser.getInstance().unregister();
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ public class DirectConnectController implements Initializable {
|
|||||||
*/
|
*/
|
||||||
private void connectToServer() {
|
private void connectToServer() {
|
||||||
//TODO fix port number validation
|
//TODO fix port number validation
|
||||||
|
|
||||||
|
try{
|
||||||
|
Integer.parseInt(portNumber.getText());
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e){
|
||||||
|
ViewManager.getInstance().showErrorSnackBar("You need to enter a valid port number");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ViewManager.getInstance().getGameClient()
|
ViewManager.getInstance().getGameClient()
|
||||||
.runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText()));
|
.runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* a separate file to dynamically change snackbar's color */
|
/* a separate file to dynamically change snackbar's color */
|
||||||
.jfx-snackbar-toast {
|
.jfx-snackbar-toast {
|
||||||
-fx-text-fill: red !important;
|
-fx-text-fill: black !important;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user