Server discovery bug fixes & error handling improvements

- Fixed concurrency bug that prevented players from connecting to servers
- Discovery server can restart itself if it crashes
- Added nicer error handling for server discovery.
- Using AWS to get servers external IP address.

Tags: #story[1281]
This commit is contained in:
Michael Rausch
2017-09-27 12:32:17 +13:00
parent 735699dc85
commit daf3867433
12 changed files with 214 additions and 147 deletions
+9 -1
View File
@@ -80,6 +80,14 @@ public class App extends Application {
ViewManager.getInstance().initialStartView(primaryStage); ViewManager.getInstance().initialStartView(primaryStage);
} }
private static void runDiscoveryServer(){
try{
new DiscoveryServer();
}
catch (Exception e){
runDiscoveryServer();
}
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try { try {
@@ -92,7 +100,7 @@ public class App extends Application {
launch(args); launch(args);
} }
else{ else{
new DiscoveryServer(); runDiscoveryServer();
} }
} }
} }
@@ -2,15 +2,19 @@ package seng302.discoveryServer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import seng302.gameServer.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RoomCodeRequest; import seng302.gameServer.messages.RoomCodeRequest;
import seng302.gameServer.messages.ServerRegistrationMessage; import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.discoveryServer.util.ServerListing; import seng302.visualiser.controllers.ViewManager;
import seng302.discoveryServer.util.ServerRepoStreamParser;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket; import java.net.Socket;
import java.net.URL;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@@ -20,9 +24,28 @@ public class DiscoveryServerClient {
private static String roomCode = null; private static String roomCode = null;
private Timer serverListingUpdateTimer; private Timer serverListingUpdateTimer;
private Logger logger = LoggerFactory.getLogger(DiscoveryServerClient.class); private Logger logger = LoggerFactory.getLogger(DiscoveryServerClient.class);
private String ip = "";
private Boolean isInInvalidState = false;
public DiscoveryServerClient() { public DiscoveryServerClient() {
try {
ip = getInetIpAddr();
} catch (Exception e) {
failError();
}
}
public String getInetIp(){
return ip;
}
private void failError() {
isInInvalidState = true;
ViewManager.getInstance().showErrorSnackBar("You do not appear to be able to connect to the internet. Matchmaking will be unavailable.");
}
public boolean didFail(){
return isInInvalidState;
} }
/** /**
@@ -30,6 +53,8 @@ public class DiscoveryServerClient {
* @param serverListing The listing to register * @param serverListing The listing to register
*/ */
public void register(ServerListing serverListing){ public void register(ServerListing serverListing){
if (isInInvalidState) return;
if (serverListingUpdateTimer != null){ if (serverListingUpdateTimer != null){
serverListingUpdateTimer.cancel(); serverListingUpdateTimer.cancel();
serverListingUpdateTimer = null; serverListingUpdateTimer = null;
@@ -53,6 +78,7 @@ public class DiscoveryServerClient {
* Stop updating the server registration updates * Stop updating the server registration updates
*/ */
public void unregister(){ public void unregister(){
if (serverListingUpdateTimer != null)
serverListingUpdateTimer.cancel(); serverListingUpdateTimer.cancel();
} }
@@ -143,5 +169,27 @@ public class DiscoveryServerClient {
public static String getRoomCode(){ public static String getRoomCode(){
return roomCode; return roomCode;
} }
public static String getInetIpAddr() throws Exception {
URL myIp = new URL("http://checkip.amazonaws.com");
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
myIp.openStream()));
String ip = in.readLine();
return ip;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} }
@@ -48,7 +48,7 @@ public class ServerTable {
updateTtlForServer(server); updateTtlForServer(server);
return; return;
} }
logger.debug("Added new server - " + server.getServerName()); logger.debug("Added new server - " + server.getServerName() + " at address: " + server.getAddress() + ":" + server.getPortNumber());
servers.add(server); servers.add(server);
} }
@@ -1,11 +1,5 @@
package seng302.gameServer; package seng302.gameServer;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.Message; import seng302.gameServer.messages.Message;
@@ -18,6 +12,13 @@ import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/** /**
* A class describing the overall server, which creates and collects server threads for each client * A class describing the overall server, which creates and collects server threads for each client
* Created by wmu16 on 13/07/17. * Created by wmu16 on 13/07/17.
@@ -158,6 +159,8 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
private void sendSetupMessages() { private void sendSetupMessages() {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
broadcastMessage(MessageFactory.getRaceXML()); broadcastMessage(MessageFactory.getRaceXML());
broadcastMessage(MessageFactory.getRegattaXML()); broadcastMessage(MessageFactory.getRegattaXML());
broadcastMessage(MessageFactory.getBoatXML()); broadcastMessage(MessageFactory.getBoatXML());
@@ -253,16 +256,26 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
}); });
} else { } else {
serverToClientThread.addConnectionListener(this::sendSetupMessages); //serverToClientThread.addConnectionListener(this::sendSetupMessages);
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
} }
serverToClientThreads.add(serverToClientThread); serverToClientThreads.add(serverToClientThread);
serverToClientThread.addDisconnectListener(this::clientDisconnected);
try { try {
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers()); ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
} catch (IOException e) { } catch (IOException e) {
logger.warn("Couldn't update advertisement"); logger.warn("Couldn't update advertisement");
} }
while (regattaXMLData == null && raceXMLData == null){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
serverToClientThread.addConnectionListener(this::sendSetupMessages);
serverToClientThread.addDisconnectListener(this::clientDisconnected);
} }
/** /**
@@ -283,6 +296,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
serverToClientThread.sendSetupMessages(); serverToClientThread.sendSetupMessages();
} }
} }
serverToClientThreads.remove(closedConnection); serverToClientThreads.remove(closedConnection);
try { try {
@@ -1,18 +1,6 @@
package seng302.gameServer; package seng302.gameServer;
import java.util.ArrayList; import seng302.gameServer.messages.*;
import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.RaceStartNotificationType;
import seng302.gameServer.messages.RaceStartStatusMessage;
import seng302.gameServer.messages.RaceStatus;
import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.messages.RaceType;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.gameServer.messages.YachtEventType;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.stream.xml.generator.RaceXMLTemplate; import seng302.model.stream.xml.generator.RaceXMLTemplate;
@@ -20,9 +8,11 @@ import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import java.util.ArrayList;
import java.util.List;
/** /**
* A Class for interfacing between the data we have in the GameState to the messages we need to send * A Class for interfacing between the data we have in the GameState to the messages we need to send
* through the MainServerThread. * through the MainServerThread.
@@ -1,7 +1,7 @@
package seng302.gameServer; package seng302.gameServer;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.DiscoveryServerClient; import seng302.discoveryServer.DiscoveryServerClient;
import seng302.discoveryServer.util.ServerListing;
import javax.jmdns.JmDNS; import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceInfo;
@@ -133,7 +133,7 @@ public class ServerAdvertiser {
} }
}, 0); }, 0);
ServerListing serverListing = new ServerListing(serverName, props.get("map"), getLocalHostIp(), portNo, Integer.parseInt(props.get("capacity"))); ServerListing serverListing = new ServerListing(serverName, props.get("map"), new DiscoveryServerClient().getInetIp(), portNo, Integer.parseInt(props.get("capacity")));
repositoryClient.register(serverListing); repositoryClient.register(serverListing);
} }
@@ -1,6 +1,21 @@
package seng302.gameServer; package seng302.gameServer;
import javafx.beans.property.SimpleObjectProperty;
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.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -12,26 +27,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.ChatterMessage;
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.model.Player;
import seng302.model.ServerYacht;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.utilities.XMLParser;
/** /**
* 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
@@ -196,6 +191,7 @@ public class ServerToClientThread implements Runnable {
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes. // TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
break; break;
case RACE_XML: case RACE_XML:
System.out.println("Got raceXML from client");
raceXMLProperty.set( raceXMLProperty.set(
XMLParser.parseRace( XMLParser.parseRace(
StreamParser.extractXmlMessage(packet) StreamParser.extractXmlMessage(packet)
@@ -1,36 +1,22 @@
package seng302.visualiser; package seng302.visualiser;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.*;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.utilities.XMLParser;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import javafx.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatActionMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.ClientType;
import seng302.gameServer.messages.CustomizeRequestMessage;
import seng302.gameServer.messages.CustomizeRequestType;
import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RegistrationRequestMessage;
import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket;
import seng302.utilities.XMLParser;
/** /**
* A class describing a single connection to a Server for the purposes of sending and receiving on * A class describing a single connection to a Server for the purposes of sending and receiving on
@@ -137,10 +123,12 @@ public class ClientToServerThread implements Runnable {
else { else {
if (clientId == -1) continue; // Do not continue if not registered if (clientId == -1) continue; // Do not continue if not registered
streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload)); streamPackets.add(new StreamPacket(type, payloadLength, timeStamp, payload));
synchronized (this) {
for (ClientSocketListener csl : listeners) for (ClientSocketListener csl : listeners)
csl.newPacket(); csl.newPacket();
} }
} }
}
} else { } else {
logger.warn("Packet has been dropped", 1); logger.warn("Packet has been dropped", 1);
} }
@@ -322,20 +310,26 @@ public class ClientToServerThread implements Runnable {
} }
public void addStreamObserver (ClientSocketListener streamListener) { public void addStreamObserver (ClientSocketListener streamListener) {
synchronized (this){
listeners.add(streamListener); listeners.add(streamListener);
} }
}
public void removeStreamObserver (ClientSocketListener streamListener) { public void removeStreamObserver (ClientSocketListener streamListener) {
listeners.remove(streamListener); listeners.remove(streamListener);
} }
public void addDisconnectionListener (DisconnectedFromHostListener listener) { public void addDisconnectionListener (DisconnectedFromHostListener listener) {
synchronized (this){
disconnectionListeners.add(listener); disconnectionListeners.add(listener);
} }
}
public void removeDisconnectionListener (DisconnectedFromHostListener listener) { public void removeDisconnectionListener (DisconnectedFromHostListener listener) {
synchronized (this){
disconnectionListeners.remove(listener); disconnectionListeners.remove(listener);
} }
}
private int readByte() throws ByteReadException { private int readByte() throws ByteReadException {
int currentByte = -1; int currentByte = -1;
@@ -1,15 +1,5 @@
package seng302.visualiser; package seng302.visualiser;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -48,6 +38,12 @@ import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController; import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
* with a JavaFX Pane to insert itself into. * with a JavaFX Pane to insert itself into.
@@ -114,7 +110,7 @@ public class GameClient {
this.lobbyController = ViewManager.getInstance().goToLobby(true); this.lobbyController = ViewManager.getInstance().goToLobby(true);
} catch (IOException ioe) { } catch (IOException ioe) {
showConnectionError("Unable to find server"); ViewManager.getInstance().showErrorSnackBar("Unable to find server");
} }
} }
@@ -2,12 +2,6 @@ package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@@ -19,6 +13,7 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import seng302.discoveryServer.DiscoveryServerClient;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
@@ -28,12 +23,17 @@ import seng302.model.RaceState;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.discoveryServer.DiscoveryServerClient;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.MapPreview; import seng302.visualiser.MapPreview;
import seng302.visualiser.controllers.cells.PlayerCell; import seng302.visualiser.controllers.cells.PlayerCell;
import seng302.visualiser.controllers.dialogs.BoatCustomizeController; import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
import seng302.visualiser.controllers.dialogs.DirectConnectController;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
public class LobbyController implements Initializable { public class LobbyController implements Initializable {
@@ -91,6 +91,17 @@ public class LobbyController implements Initializable {
serverName.setText(ViewManager.getInstance().getProperty("serverName")); serverName.setText(ViewManager.getInstance().getProperty("serverName"));
mapName.setText(ViewManager.getInstance().getProperty("mapName")); mapName.setText(ViewManager.getInstance().getProperty("mapName"));
int tries = 0;
while (DiscoveryServerClient.getRoomCode() == null && tries <= 10){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tries ++;
}
if (DiscoveryServerClient.getRoomCode() != null){ if (DiscoveryServerClient.getRoomCode() != null){
setRoomCode(DiscoveryServerClient.getRoomCode()); setRoomCode(DiscoveryServerClient.getRoomCode());
} }
@@ -5,17 +5,11 @@ import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialog.DialogTransition; import com.jfoenix.controls.JFXDialog.DialogTransition;
import com.jfoenix.controls.JFXTextField; import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
@@ -23,19 +17,21 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServer;
import seng302.gameServer.ServerDescription;
import seng302.discoveryServer.util.ServerListing;
import seng302.discoveryServer.DiscoveryServerClient; import seng302.discoveryServer.DiscoveryServerClient;
import seng302.gameServer.messages.RoomCodeRequest; import seng302.discoveryServer.util.ServerListing;
import seng302.gameServer.ServerDescription;
import seng302.gameServer.messages.ServerRegistrationMessage;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListener;
import seng302.visualiser.ServerListenerDelegate; import seng302.visualiser.ServerListenerDelegate;
import seng302.visualiser.controllers.cells.ServerCell; import seng302.visualiser.controllers.cells.ServerCell;
import seng302.visualiser.controllers.dialogs.DirectConnectController; import seng302.visualiser.controllers.dialogs.DirectConnectController;
import seng302.visualiser.validators.HostNameFieldValidator;
import seng302.visualiser.validators.NumberRangeValidator; import java.io.IOException;
import seng302.visualiser.validators.ValidationTools; import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
public class ServerListController implements Initializable, ServerListenerDelegate { public class ServerListController implements Initializable, ServerListenerDelegate {
@@ -90,6 +86,8 @@ public class ServerListController implements Initializable, ServerListenerDelega
Sounds.playButtonClick(); Sounds.playButtonClick();
}); });
directConnectDialog = createDirectConnectDialog();
for (JFXTextField textField : Arrays.asList(roomNumber)) { for (JFXTextField textField : Arrays.asList(roomNumber)) {
// Event for pressing enter to submit direct connection // Event for pressing enter to submit direct connection
textField.setOnKeyPressed(event -> { textField.setOnKeyPressed(event -> {
@@ -105,26 +103,26 @@ public class ServerListController implements Initializable, ServerListenerDelega
} }
autoSelectGame.setOnMouseReleased(e -> { autoSelectGame.setOnMouseReleased(e -> {
try { ServerListing listing;
ServerListing listing = new DiscoveryServerClient().getRandomServer(); DiscoveryServerClient client = new DiscoveryServerClient();
if (listing == null){ try {
Alert alert = new Alert(Alert.AlertType.ERROR); listing = client.getRandomServer();
alert.setHeaderText("Error finding game");
alert.setContentText("No servers are up");
alert.showAndWait();
}
else{
ViewManager.getInstance().getGameClient().runAsClient(listing.getAddress(), listing.getPortNumber());
}
} catch (Exception e1) { } catch (Exception e1) {
e1.printStackTrace(); ViewManager.getInstance().showErrorSnackBar("Unable to connect to matchmaking server. Are you connected to the internet?");
logger.error("Error getting listing"); return;
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Error finding game");
alert.setContentText("Couldn't contact matchmaking server");
alert.showAndWait();
} }
if (client.didFail()){
return;
}
if (listing == null || listing.equals(ServerRegistrationMessage.getEmptyRegistration())) {
ViewManager.getInstance().showErrorSnackBar("There are currently no servers available for you to connect to.");
return;
}
ViewManager.getInstance().getGameClient().runAsClient(listing.getAddress(), listing.getPortNumber());
}); });
/* /*
@@ -186,9 +184,6 @@ public class ServerListController implements Initializable, ServerListenerDelega
e.printStackTrace(); e.printStackTrace();
logger.warn("Could not create Server Creation Dialog."); logger.warn("Could not create Server Creation Dialog.");
} }
directConnectDialog = createDirectConnectDialog();
}); });
} }
@@ -235,20 +230,30 @@ public class ServerListController implements Initializable, ServerListenerDelega
} }
private void connectToRoomCode(String roomCode){ private void connectToRoomCode(String roomCode){
DiscoveryServerClient client = new DiscoveryServerClient();
ServerListing serverListing;
if (client.didFail()){
return;
}
try {
serverListing = client.getServerForRoomCode(roomCode);
} catch (Exception e) {
ViewManager.getInstance().showErrorSnackBar("Error connecting to matchmaking server. Please try again later.");
return;
}
if (serverListing == null || serverListing.equals(new ServerListing("","","", 0, 0))){
ViewManager.getInstance().showErrorSnackBar("No servers could be found with that room code.");
return;
}
try { try {
ServerListing serverListing = new DiscoveryServerClient().getServerForRoomCode(roomCode);
ViewManager.getInstance().getGameClient().runAsClient(serverListing.getAddress(), serverListing.getPortNumber()); ViewManager.getInstance().getGameClient().runAsClient(serverListing.getAddress(), serverListing.getPortNumber());
} }
catch (java.net.ConnectException e){
//TODO Add proper dialog
logger.warn("Couldn't connect to discovery server");
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Couldn't connect to discovery server");
alert.setContentText("Couldn't connect to " + DiscoveryServer.DISCOVERY_SERVER);
alert.showAndWait();
}
catch (Exception e) { catch (Exception e) {
logger.warn("Error discovering room code"); ViewManager.getInstance().showErrorSnackBar("Error connecting to matchmaking service.");
} }
} }
@@ -6,16 +6,10 @@ import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialog.DialogTransition; import com.jfoenix.controls.JFXDialog.DialogTransition;
import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.controls.JFXSnackbar;
import com.jfoenix.svg.SVGGlyph; import com.jfoenix.svg.SVGGlyph;
import java.io.IOException;
import java.util.HashMap;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor; import javafx.scene.*;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
@@ -28,6 +22,9 @@ import seng302.utilities.Sounds;
import seng302.visualiser.GameClient; import seng302.visualiser.GameClient;
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
import java.io.IOException;
import java.util.HashMap;
public class ViewManager { public class ViewManager {
private static ViewManager instance; private static ViewManager instance;
@@ -369,6 +366,14 @@ public class ViewManager {
return loader.getController(); return loader.getController();
} }
public void showErrorSnackBar(String msg){
decorator.getStylesheets()
.add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm());
JFXSnackbar bar = new JFXSnackbar(decorator);
bar.enqueue(new JFXSnackbar.SnackbarEvent(msg));
}
public Stage getStage() { public Stage getStage() {
return stage; return stage;
} }