From 5207a6a0bcf59dc747fae349aee58744e3b1255c Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Mon, 27 Apr 2020 09:57:23 +0200 Subject: [PATCH] =?UTF-8?q?Oppdaterer=20server=20og=20klient=20for=20?= =?UTF-8?q?=C3=A5=20kunne=20sjekke=20om=20en=20foresp=C3=B8rsel=20ble=20go?= =?UTF-8?q?dkjent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oppdaterer brukernavn-skjermen til å bekrefte at brukernavnet ble godkjent --- .../gamewrapper/screens/UsernameScreen.java | 28 +++-- .../roborally/networking/RequestState.java | 23 ++++ .../roborally/networking/RoboRallyClient.java | 14 ++- .../networking/RoboRallyClientListener.java | 117 ++++++++++++++---- .../networking/RoboRallyServerListener.java | 19 +-- .../networking/containers/OkayResponse.java | 13 ++ .../containers/UsernameRequest.java | 33 +++++ .../fiasko/roborally/utility/NetworkUtil.java | 6 +- 8 files changed, 210 insertions(+), 43 deletions(-) create mode 100644 src/main/java/inf112/fiasko/roborally/networking/RequestState.java create mode 100644 src/main/java/inf112/fiasko/roborally/networking/containers/OkayResponse.java create mode 100644 src/main/java/inf112/fiasko/roborally/networking/containers/UsernameRequest.java diff --git a/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/UsernameScreen.java b/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/UsernameScreen.java index 63b0e11..400ddb1 100644 --- a/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/UsernameScreen.java +++ b/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/UsernameScreen.java @@ -8,8 +8,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextField; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.viewport.FitViewport; import inf112.fiasko.roborally.gamewrapper.RoboRallyWrapper; +import inf112.fiasko.roborally.networking.RequestState; +import inf112.fiasko.roborally.networking.containers.UsernameRequest; import javax.swing.*; +import java.util.concurrent.TimeUnit; /** * This screen allows a user to choose their player name @@ -37,10 +40,9 @@ public class UsernameScreen extends AbstractScreen { @Override public void touchUp(InputEvent e, float x, float y, int point, int button) { - String userName = textInput.getText(); - if (nameInvalid(userName)) { - JOptionPane.showMessageDialog(null, "Username cannot be empty or more " + - "than 20 characters."); + if (nameInvalid(textInput.getText())) { + JOptionPane.showMessageDialog(null, "Username must be unique, not " + + "empty and less than 21 characters."); return; } if (roboRallyWrapper.server == null) { @@ -48,7 +50,7 @@ public class UsernameScreen extends AbstractScreen { } else { roboRallyWrapper.setScreen(roboRallyWrapper.screenManager.getLobbyScreen(roboRallyWrapper)); } - roboRallyWrapper.client.sendElement(userName); + } }); textInput = new TextField("", skin); @@ -70,8 +72,20 @@ public class UsernameScreen extends AbstractScreen { * @return False if the username can be used */ private boolean nameInvalid(String userName) { - //TODO: Find a way to ask the server if the name is taken - return "".equals(userName) || userName.length() > 20; + if ("".equals(userName) || userName.length() > 20) { + return true; + } + UsernameRequest usernameRequest = new UsernameRequest(userName); + roboRallyWrapper.client.sendElement(usernameRequest); + while (roboRallyWrapper.client.getLastRequestState() == RequestState.SENT_NOT_RECEIVED) { + //Wait for the server to respond + try { + TimeUnit.MILLISECONDS.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return roboRallyWrapper.client.getLastRequestState() == RequestState.SENT_REJECTED; } @Override diff --git a/src/main/java/inf112/fiasko/roborally/networking/RequestState.java b/src/main/java/inf112/fiasko/roborally/networking/RequestState.java new file mode 100644 index 0000000..7cbc861 --- /dev/null +++ b/src/main/java/inf112/fiasko/roborally/networking/RequestState.java @@ -0,0 +1,23 @@ +package inf112.fiasko.roborally.networking; + +/** + * This enum represents states of a request sent to the server + */ +public enum RequestState { + /** + * The request has been send to the server, but no response has been received + */ + SENT_NOT_RECEIVED, + /** + * The request has been sent to the server, and the server confirmed the receipt + */ + SENT_OKAY, + /** + * The request has been sent to the server, but the server rejected the request + */ + SENT_REJECTED, + /** + * No request has been sent to the server + */ + NOT_SENT +} diff --git a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClient.java b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClient.java index efd5f24..e1dd3f0 100644 --- a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClient.java +++ b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClient.java @@ -14,6 +14,7 @@ import java.util.List; public class RoboRallyClient { private final Client client; private final RoboRallyWrapper wrapper; + private RoboRallyClientListener listener; /** * Instantiates a new Robo Rally client @@ -25,7 +26,8 @@ public class RoboRallyClient { client = new Client(); client.start(); NetworkUtil.registerClasses(client.getKryo()); - client.addListener(new RoboRallyClientListener(wrapper)); + this.listener = new RoboRallyClientListener(wrapper); + client.addListener(this.listener); } /** @@ -49,6 +51,15 @@ public class RoboRallyClient { return client.discoverHosts(wrapper.discoverUDPPort, 1000); } + /** + * Gets the state of the lastly sent request + * + * @return The state of the lastly sent request + */ + public RequestState getLastRequestState() { + return this.listener.getLastRequestState(); + } + /** * Sends something to the server * @@ -57,6 +68,7 @@ public class RoboRallyClient { public void sendElement(Object object) { try { client.sendTCP(object); + listener.resetLastRequestState(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java index 0c496e7..faa60d4 100644 --- a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java +++ b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java @@ -6,6 +6,7 @@ import inf112.fiasko.roborally.elementproperties.GameState; import inf112.fiasko.roborally.gamewrapper.RoboRallyWrapper; import inf112.fiasko.roborally.networking.containers.ErrorResponse; import inf112.fiasko.roborally.networking.containers.GameStartInfoResponse; +import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; import inf112.fiasko.roborally.objects.ProgrammingCardDeck; @@ -18,6 +19,7 @@ import java.util.ArrayList; */ class RoboRallyClientListener extends Listener { private final RoboRallyWrapper wrapper; + private RequestState lastRequestState = RequestState.NOT_SENT; /** * Instantiates a new Robo Rally client listener @@ -29,6 +31,31 @@ class RoboRallyClientListener extends Listener { this.wrapper = wrapper; } + /** + * Gets the robo rally wrapper stored + * + * @return A robo rally wrapper + */ + public RoboRallyWrapper getWrapper() { + return wrapper; + } + + /** + * Gets the state of the lastly sent request + * + * @return The state of the lastly sent request + */ + public RequestState getLastRequestState() { + return lastRequestState; + } + + /** + * Resets the state of the last request to sent not received + */ + public void resetLastRequestState() { + this.lastRequestState = RequestState.SENT_NOT_RECEIVED; + } + @Override public void disconnected(Connection connection) { this.wrapper.quit("The server closed the connection."); @@ -37,40 +64,76 @@ class RoboRallyClientListener extends Listener { @Override public void received(Connection connection, Object object) { if (object instanceof ErrorResponse) { - ErrorResponse errorResponse = (ErrorResponse) object; - if (errorResponse.isCritical()) { - wrapper.quit(errorResponse.getErrorMessage()); - } - System.out.println(errorResponse.getErrorMessage()); + handleError((ErrorResponse) object); } else if (object instanceof GameStartInfoResponse) { - GameStartInfoResponse info = (GameStartInfoResponse) object; - wrapper.roboRallyGame = new RoboRallyGame(info.getPlayerList(), info.getBoardName(), - wrapper.server != null, info.getPlayerName(), wrapper.server); - new Thread(() -> wrapper.roboRallyGame.runTurn()).start(); + receiveGameStartInfo((GameStartInfoResponse) object); } else if (object instanceof ProgrammingCardDeck) { - if (((ProgrammingCardDeck) object).isEmpty()) { - wrapper.roboRallyGame.setProgram(new ArrayList<>()); - if (wrapper.roboRallyGame.getRobotPowerDown()) { - wrapper.roboRallyGame.setGameState(GameState.SKIP_POWER_DOWN_SCREEN); - } else { - wrapper.roboRallyGame.setGameState(GameState.CHOOSING_POWER_DOWN); - } - } else { - wrapper.roboRallyGame.setGameState(GameState.CHOOSING_CARDS); - } - wrapper.roboRallyGame.setPlayerHand((ProgrammingCardDeck) object); + receiveHand((ProgrammingCardDeck) object); } else if (object instanceof ProgramsContainerResponse) { - new Thread(() -> { - try { - wrapper.roboRallyGame.receiveAllPrograms((ProgramsContainerResponse) object); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }).start(); + receivePrograms((ProgramsContainerResponse) object); } else if (object instanceof PowerDownContainerResponse) { new Thread(() -> wrapper.roboRallyGame.receiveStayInPowerDown((PowerDownContainerResponse) object)).start(); + } else if (object instanceof OkayResponse) { + this.lastRequestState = RequestState.SENT_OKAY; } + } + /** + * Handle an error received from the server + * + * @param errorResponse The error response received + */ + private void handleError(ErrorResponse errorResponse) { + this.lastRequestState = RequestState.SENT_REJECTED; + if (errorResponse.isCritical()) { + wrapper.quit(errorResponse.getErrorMessage()); + } + System.out.println(errorResponse.getErrorMessage()); + } + + /** + * Receive information about the game and start the turn + * + * @param info The information received from the server + */ + private void receiveGameStartInfo(GameStartInfoResponse info) { + wrapper.roboRallyGame = new RoboRallyGame(info.getPlayerList(), info.getBoardName(), + wrapper.server != null, info.getPlayerName(), wrapper.server); + new Thread(() -> wrapper.roboRallyGame.runTurn()).start(); + } + + /** + * Receive a hand from the server + * + * @param newHand The new hand this client can choose from + */ + private void receiveHand(ProgrammingCardDeck newHand) { + if (newHand.isEmpty()) { + wrapper.roboRallyGame.setProgram(new ArrayList<>()); + if (wrapper.roboRallyGame.getRobotPowerDown()) { + wrapper.roboRallyGame.setGameState(GameState.SKIP_POWER_DOWN_SCREEN); + } else { + wrapper.roboRallyGame.setGameState(GameState.CHOOSING_POWER_DOWN); + } + } else { + wrapper.roboRallyGame.setGameState(GameState.CHOOSING_CARDS); + } + wrapper.roboRallyGame.setPlayerHand(newHand); + } + + /** + * Receive and handle programs send from server + * + * @param response The response received from the server + */ + private void receivePrograms(ProgramsContainerResponse response) { + new Thread(() -> { + try { + wrapper.roboRallyGame.receiveAllPrograms(response); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); } } diff --git a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java index 84866fe..c38cab9 100644 --- a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java +++ b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java @@ -5,9 +5,11 @@ import com.esotericsoftware.kryonet.Connection; import com.esotericsoftware.kryonet.Listener; import inf112.fiasko.roborally.elementproperties.RobotID; import inf112.fiasko.roborally.networking.containers.ErrorResponse; +import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; -import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramAndPowerdownRequest; +import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; +import inf112.fiasko.roborally.networking.containers.UsernameRequest; import inf112.fiasko.roborally.objects.ProgrammingCard; import java.util.ArrayList; @@ -105,8 +107,8 @@ class RoboRallyServerListener extends Listener { @Override public void received(Connection connection, Object object) { - if (object instanceof String) { - receivedString(connection, (String) object); + if (object instanceof UsernameRequest) { + receivedUsername(connection, (UsernameRequest) object); } else if (object instanceof Boolean) { receiveContinuePowerDown(connection, (Boolean) object); } else if (object instanceof ProgramAndPowerdownRequest) { @@ -118,13 +120,14 @@ class RoboRallyServerListener extends Listener { * Handles the receiving of a string, handled as a player name in this context * * @param connection The connection sending the string - * @param playerName The player name received + * @param request The username request received */ - private void receivedString(Connection connection, String playerName) { + private void receivedUsername(Connection connection, UsernameRequest request) { + String playerName = request.getUsername(); if (playerNames.containsValue(playerName)) { - String errorMessage = "The player playerName send is already taken."; - connection.sendTCP(new ErrorResponse(errorMessage)); + connection.sendTCP(new ErrorResponse("The player playerName sent is already taken.")); } else { + connection.sendTCP(new OkayResponse()); playerNames.put(connection, playerName); } } @@ -137,6 +140,7 @@ class RoboRallyServerListener extends Listener { */ private void receiveContinuePowerDown(Connection connection, Boolean bool) { stayInPowerDown.put(connection, bool); + connection.sendTCP(new OkayResponse()); if (receivedDataFromAllConnections(stayInPowerDown)) { Map powerDowns = new HashMap<>(); for (Connection connected : stayInPowerDown.keySet()) { @@ -155,6 +159,7 @@ class RoboRallyServerListener extends Listener { */ private void receiveProgramAndPowerDownRequest(Connection connection, ProgramAndPowerdownRequest request) { programs.put(connection, request); + connection.sendTCP(new OkayResponse()); if (receivedDataFromAllConnections(programs)) { Map powerDown = new HashMap<>(); Map> program = new HashMap<>(); diff --git a/src/main/java/inf112/fiasko/roborally/networking/containers/OkayResponse.java b/src/main/java/inf112/fiasko/roborally/networking/containers/OkayResponse.java new file mode 100644 index 0000000..1071e30 --- /dev/null +++ b/src/main/java/inf112/fiasko/roborally/networking/containers/OkayResponse.java @@ -0,0 +1,13 @@ +package inf112.fiasko.roborally.networking.containers; + +/** + * An empty response telling the client its request was fulfilled + */ +public class OkayResponse { + + /** + * Empty constructor required by KryoNet. DO NOT REMOVE THIS!!! + */ + public OkayResponse() { + } +} diff --git a/src/main/java/inf112/fiasko/roborally/networking/containers/UsernameRequest.java b/src/main/java/inf112/fiasko/roborally/networking/containers/UsernameRequest.java new file mode 100644 index 0000000..472c225 --- /dev/null +++ b/src/main/java/inf112/fiasko/roborally/networking/containers/UsernameRequest.java @@ -0,0 +1,33 @@ +package inf112.fiasko.roborally.networking.containers; + +/** + * A request for sending a username to the server + */ +public class UsernameRequest { + private String username; + + /** + * Empty constructor required by KryoNet. DO NOT REMOVE THIS!!! + */ + public UsernameRequest() { + + } + + /** + * Instantiates a new username request + * + * @param username The username the player wants to use + */ + public UsernameRequest(String username) { + this.username = username; + } + + /** + * Gets the username the user wants to use + * + * @return The username the user wants to use + */ + public String getUsername() { + return this.username; + } +} diff --git a/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java b/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java index cc2966f..cca2f20 100644 --- a/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java +++ b/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java @@ -5,9 +5,11 @@ import inf112.fiasko.roborally.elementproperties.Action; import inf112.fiasko.roborally.elementproperties.RobotID; import inf112.fiasko.roborally.networking.containers.ErrorResponse; import inf112.fiasko.roborally.networking.containers.GameStartInfoResponse; +import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; -import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramAndPowerdownRequest; +import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; +import inf112.fiasko.roborally.networking.containers.UsernameRequest; import inf112.fiasko.roborally.objects.Deck; import inf112.fiasko.roborally.objects.Player; import inf112.fiasko.roborally.objects.ProgrammingCard; @@ -40,5 +42,7 @@ public final class NetworkUtil { kryo.register(ProgramsContainerResponse.class); kryo.register(PowerDownContainerResponse.class); kryo.register(HashMap.class); + kryo.register(UsernameRequest.class); + kryo.register(OkayResponse.class); } }