diff --git a/.github/images/Cover.png b/.github/images/Cover.png new file mode 100644 index 00000000..5c05d798 Binary files /dev/null and b/.github/images/Cover.png differ diff --git a/.github/images/GUI.png b/.github/images/GUI.png new file mode 100644 index 00000000..ac080770 Binary files /dev/null and b/.github/images/GUI.png differ diff --git a/README.md b/README.md index 4acb27cb..82776814 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,41 @@ -# Software Engineering Project - A.A. 2023/2024 +# Codex Naturalis πŸŒΏπŸ„πŸ¦‹πŸΊ -## AM32 Group +## About -Group members: + +Codex Naturalis is the final project of the "Software Engineering" course held at Politecnico di Milano (A.Y. 2023/2024). + +The group members are: + +- Matteo Bergagna - Antony Brun - Lorenzo Chiroli - Jie Chen -- Matteo Bergagna - -## Project Status - -### General - -| Tasks | Status | Notes | -|------------------------|--------|---------------------------------| -| UML (Class Diagram) | β˜‘οΈ | Model + Controller + Networking | -| UML (Sequence Diagram) | β˜‘οΈ | Communication Protocol | -| Peer Review 1 | β˜‘οΈ | Model | -| Peer Review 2 | β˜‘οΈ | Communication Protocol | -### Server +## Game Screenshot +

+ +

-| Feature | Status | Notes | -|------------|--------|----------------| -| Model | β˜‘οΈ | Complete Rules | -| Controller | β˜‘οΈ | N/A | -| Networking | β˜‘οΈ | RMI + Socket | - -| Advanced Features | Status | Notes | -|------------------------------|--------|-----------------------| -| Multiple Matches | β˜‘οΈ | N/A | -| Resilience to Disconnections | β˜‘οΈ | N/A | -| Chat | β˜‘οΈ | N/A | +## Project Status -### Client +| Satisfied Requirements | Maximum Grade | Status | +|-----------------------------------------------------------------------------------------------------|---------------|--------| +| Simplified Rules + TUI + RMI or Socket | 18 | β˜‘οΈ | +| Complete Rules + TUI + RMI or Socket | 20 | β˜‘οΈ | +| Complete Rules + TUI + RMI or Socket + 1 FA (Chat) | 22 | β˜‘οΈ | +| Complete Rules + TUI + GUI + RMI or Socket + 1 FA (Chat) | 24 | β˜‘οΈ | +| Complete Rules + TUI + GUI + RMI + Socket + 1 FA (Chat) | 27 | β˜‘οΈ | +| Complete Rules + TUI + GUI + RMI + Socket + 2 FA (Chat & Multiple match) | 30 | β˜‘οΈ | +| Complete Rules + TUI + GUI + RMI + Socket + 3 FA (Chat & Multiple match & Disconnection resilience) | 30L | ⚠️ | -| Feature | Status | Notes | -|------------|--------|------------------| -| Networking | πŸ•‘ | Socket only RN! | -| TUI | β˜‘οΈ | N/A | -| GUI | ‼️ | Not yet started! | +### Currently Known Issues -| Advanced Features | Status | Notes | -|------------------------------|--------|----------------| -| Multiple Matches | β˜‘οΈ | N/A | -| Resilience to Disconnections | πŸ•‘ | Working on it! | -| Chat | β˜‘οΈ | N/A | +- 🟨 The branch with the correct version of the network stack is not yet merged. Therefore, the network is not informing the View if the initial connection was successful or not. +- πŸŸ₯ The branch with the correct version of the network stack is not yet merged. Therefore, the network is not activating the PingTask that allows (in both Client & Server) the disconnection discovery in RMI. ## Code Coverage -| Package | Role | Coverage (%Methods) | Coverage (%Line) | Testing Status | -|-------------|----------------------|---------------------|------------------|----------------| -| .model | Game Model | 100% | 97% | Completed β˜‘οΈ | -| .chat | Chat Model | 100% | 100% | Completed β˜‘οΈ | -| .controller | Game+Chat Controller | 90% | 63% | Ongoing πŸ•‘ | +The average code coverage, between Model and Controller, is 96% for methods and 85% for lines, all (known) edge cases are covered. +The coverage is calculated using the IntelliJ IDEA built-in tool. diff --git a/src/main/java/it/polimi/ingsw/am32/client/Event.java b/src/main/java/it/polimi/ingsw/am32/client/Event.java index 4e83a027..97e92a19 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/Event.java +++ b/src/main/java/it/polimi/ingsw/am32/client/Event.java @@ -4,12 +4,12 @@ * Enumeration of the possible events that can occur during the game. */ public enum Event { - LOBBY(0), - PREPARATION(1), - PLAYING(2), - TERMINATING(3), - LAST_TURN(4), - TERMINATED(5), + LOBBY(0), // STATUS + PREPARATION(1), // STATUS + PLAYING(2), // STATUS + TERMINATING(3), // STATUS + LAST_TURN(4), // STATUS + TERMINATED(5), // STATUS CHOOSE_CONNECTION (6), SELECT_GAME_MODE(7), CREATE_GAME(8), @@ -31,12 +31,16 @@ public enum Event { DRAW_CARD(24), PLAYER_RECONNECTED(25), DRAW_CARD_FAILURE(26), - WELCOME(27), + WELCOME(27), // STATUS SELECTED_STARTER_CARD_SIDE(28), SELECTED_SECRET_OBJ_CARD(29), CARD_PLACED(30), CARD_DRAWN(31), - WAITING_FOR_TURN(32), CHAT_ERROR(33); + WAITING_FOR_TURN(32), + CHAT_ERROR(33), + CREATE_GAME_FAILURE(34), + JOIN_GAME_FAILURE(35), + RECONNECT_GAME_FAILURE(36); private final int value; diff --git a/src/main/java/it/polimi/ingsw/am32/client/NonObjCardFactory.java b/src/main/java/it/polimi/ingsw/am32/client/NonObjCardFactory.java index 939e5cee..9175e7a7 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/NonObjCardFactory.java +++ b/src/main/java/it/polimi/ingsw/am32/client/NonObjCardFactory.java @@ -59,6 +59,10 @@ public NonObjCardFactory(String cardType,int ID, int Value, String PointStrategy this.ConditionCount=ConditionCount; } + /** + * This method is used to create the cards from the JSON file. + * @return an ArrayList containing the cards + */ public static ArrayList setNonObjCardArray() { // Initialize the ArrayList to store the cards ArrayList NonObjCards = new ArrayList<>(); diff --git a/src/main/java/it/polimi/ingsw/am32/client/PlayerPub.java b/src/main/java/it/polimi/ingsw/am32/client/PlayerPub.java index f06c95a7..9bc9a404 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/PlayerPub.java +++ b/src/main/java/it/polimi/ingsw/am32/client/PlayerPub.java @@ -84,6 +84,7 @@ public void updateResources(int[] resources){ } /** * Update the points of the player with the points updated received from the message. + * @param points the new version of the points. */ public void updatePoints(int points){ this.points = points; diff --git a/src/main/java/it/polimi/ingsw/am32/client/View.java b/src/main/java/it/polimi/ingsw/am32/client/View.java index 78cc3957..303f7735 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/View.java +++ b/src/main/java/it/polimi/ingsw/am32/client/View.java @@ -1,6 +1,7 @@ package it.polimi.ingsw.am32.client; +import it.polimi.ingsw.am32.network.exceptions.ConnectionSetupFailedException; import it.polimi.ingsw.am32.utilities.IsValid; import it.polimi.ingsw.am32.client.listener.AskListener; import it.polimi.ingsw.am32.message.ClientToServer.CtoSLobbyMessage; @@ -9,7 +10,6 @@ import it.polimi.ingsw.am32.network.ClientNode.RMIClientNode; import it.polimi.ingsw.am32.network.ClientNode.SKClientNode; -import java.io.IOException; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Collections; @@ -170,16 +170,16 @@ public View() { * Also, it creates a new thread to listen for messages from the client. * @param serverIP The IP address of the server. * @param port The port number of the server. - * @throws IOException If an I/O error occurs when creating the socket. + * @throws ConnectionSetupFailedException if the connection setup fails. */ - public void setSocketClient(String serverIP, int port) throws IOException { + public void setSocketClient(String serverIP, int port) throws ConnectionSetupFailedException { SKClientNode clientNode = new SKClientNode(this,serverIP,port); this.clientNode = clientNode; clientNode.startConnection(); - this.askListener = new AskListener(clientNode); + + this.askListener = new AskListener(clientNode); Thread askListener = new Thread(this.askListener); // Create a new thread listen for messages from the client askListener.start(); - //TODO verify if this is correct } /** @@ -187,9 +187,9 @@ public void setSocketClient(String serverIP, int port) throws IOException { * Also, it creates a new thread to listen for messages from the client. * @param serverIP The IP address of the server. * @param port The port number of the server. + * @throws ConnectionSetupFailedException if the connection setup fails. */ - public void setRMIClient(String serverIP, int port) { - //TODO verify if this is correct + public void setRMIClient(String serverIP, int port) throws ConnectionSetupFailedException { try{ RMIClientNode clientNode = new RMIClientNode(this, serverIP, port); this.clientNode = clientNode; @@ -199,7 +199,7 @@ public void setRMIClient(String serverIP, int port) { Thread askListenerThread = new Thread(this.askListener); askListenerThread.start(); }catch (RemoteException e) { - //TODO + throw new ConnectionSetupFailedException(); } } /** @@ -514,6 +514,10 @@ public abstract void updateRollback(String playerNickname, int removedCard, int * @param nickname The nickname of the player will be used to handle the event. */ public abstract void handleEvent(Event event, String nickname); + + public abstract void nodeDisconnected(); + + public abstract void nodeReconnected(); } diff --git a/src/main/java/it/polimi/ingsw/am32/client/view/gui/ChatArea.java b/src/main/java/it/polimi/ingsw/am32/client/view/gui/ChatArea.java index 0c3dbba7..f127333e 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/view/gui/ChatArea.java +++ b/src/main/java/it/polimi/ingsw/am32/client/view/gui/ChatArea.java @@ -6,7 +6,11 @@ import java.util.ArrayList; - +/** + * This class represents the chat area in the GUI. + * It contains the message display area, the message input area, and the submit button. + * It also contains a combo box that allows the user to select a recipient for the message. + */ public class ChatArea { /** * An object representing the chat area in the GUI @@ -45,7 +49,7 @@ public class ChatArea { /** * Constructor for the ChatArea class - * + * @param gui A reference to the GUI * @param X X coordinate of the chat area * @param Y Y coordinate of the chat area * @param width Width of the chat area @@ -136,8 +140,8 @@ private void initializeChatArea(int X, int Y, int width, int height, ArrayList { selectionPane.getChildren().remove(connectionRoot); // exit from the choose connection page selectionPane.getChildren().add(socketRoot); // enter the socket connection page }); OkButton.setOnAction(e -> { + OkButton.setDisable(true); String ServerIP = ip.getText(); // Read the player's input and save it the server IP address String ServerPort = port.getText(); try { @@ -406,26 +410,29 @@ public void chooseConnection() { selectionPane.getChildren().remove(socketRoot); askSelectGameMode(); } else { - createAlert("Invalid IP/port number"); + createAlert("Invalid IP or PORT number!"); ip.clear(); port.clear(); } } catch (NumberFormatException ex) { - createAlert("Invalid port number"); + createAlert("Invalid PORT number!"); port.clear(); - } catch (IOException ex) { - createAlert("Connection failed"); + } catch (ConnectionSetupFailedException ex) { + createAlert("Connection failed! You can try again!"); ip.clear(); port.clear(); } + OkButton.setDisable(false); }); - // set the action of the buttons + + // set the action of the buttons (RMI) rmiButton.setOnAction(e -> { selectionPane.getChildren().remove(connectionRoot); // exit from the choose connection page selectionPane.getChildren().add(RMIRoot); // enter the socket connection page }); OkRMIButton.setOnAction(e -> { + OkRMIButton.setDisable(true); String ServerIP = RMIIp.getText(); // Read the player's input and save it the server IP address String ServerPort = RMIPort.getText(); try { @@ -436,36 +443,41 @@ public void chooseConnection() { askSelectGameMode(); } else { createAlert("Invalid IP/port number"); - ip.clear(); - port.clear(); + RMIIp.clear(); + RMIPort.clear(); } } catch (NumberFormatException ex) { createAlert("Invalid port number"); - port.clear(); - } /*catch (IOException ex) { //TODO - createAlert("Connection failed"); - ip.clear(); - port.clear(); - }*/ + RMIPort.clear(); + } catch (ConnectionSetupFailedException ex) { + createAlert("Connection failed! You can try again!"); + RMIIp.clear(); + RMIPort.clear(); + } + OkRMIButton.setDisable(false); }); } + /** * Set the socket connection between the client and the server. - * * @param ServerIP the IP address of the server * @param portNumber the port number of the server - * @throws IOException if the connection to the server fails */ @Override - public void setSocketClient(String ServerIP, int portNumber) throws IOException { + public void setSocketClient(String ServerIP, int portNumber) throws ConnectionSetupFailedException { super.setSocketClient(ServerIP, portNumber); } + + /** + * Set the RMI connection between the client and the server. + * @param serverURL the URL of the server + * @param port the port number of the server + */ @Override - public void setRMIClient(String serverURL, int port) { - super.setRMIClient(serverURL, port); // see the method in the superclass + public void setRMIClient(String serverURL, int port) throws ConnectionSetupFailedException { + super.setRMIClient(serverURL, port); } - /** * Set the page where the player can select the game mode. The player can choose between creating a new game, joining * an existing game or reconnecting to a game. The player can choose the game mode using the buttons β€œNew Game”, β€œJoin @@ -2187,9 +2199,9 @@ public String convertToColour(int colour) { /** * Generates the selection area for the initial card side selection. - * The selection area is composed of a prompt label, 2 cards to choose from - * - * @return a VBox containing the selection area for the initial card side selection + * The selection area is composed of a prompt label, 2 cards to choose from. + * @param imageNumber the number of the image to load. + * @return a VBox containing the selection area for the initial card side selection. */ public VBox setupInitialCardSideSelectionArea(int imageNumber) { VBox selectionArea = new VBox(); // Entire selection area @@ -2256,8 +2268,9 @@ public VBox setupInitialCardSideSelectionArea(int imageNumber) { /** * Generates the selection area for the secret objective card selection. - * The selection area is composed of a prompt label, 2 cards to choose from - * + * The selection area is composed of a prompt label, 2 cards to choose from. + * @param card1 the ID of the first card + * @param card2 the ID of the second card * @return a VBox containing the selection area for the secret objective card selection */ public VBox setupSecretObjectiveCardSelectionArea(int card1, int card2) { @@ -2346,4 +2359,11 @@ private void handleButtonClick(Button clickedButton, Button button1, Button butt public String getThisPlayerNickname() { return thisPlayerNickname; } + + // TODO implementare metodo + public void nodeDisconnected(){} + + // TODO implementare metodo + public void nodeReconnected(){} + } diff --git a/src/main/java/it/polimi/ingsw/am32/client/view/tui/TextUI.java b/src/main/java/it/polimi/ingsw/am32/client/view/tui/TextUI.java index c166e7b2..6aaeb4c0 100644 --- a/src/main/java/it/polimi/ingsw/am32/client/view/tui/TextUI.java +++ b/src/main/java/it/polimi/ingsw/am32/client/view/tui/TextUI.java @@ -1,11 +1,10 @@ package it.polimi.ingsw.am32.client.view.tui; +import it.polimi.ingsw.am32.network.exceptions.ConnectionSetupFailedException; import it.polimi.ingsw.am32.utilities.IsValid; -import it.polimi.ingsw.am32.client.ChatMessage; import it.polimi.ingsw.am32.client.*; import it.polimi.ingsw.am32.message.ClientToServer.*; -import java.io.IOException; import java.io.PrintStream; import java.util.*; @@ -31,7 +30,7 @@ * For the design of the cards, the class includes a method to print the card, a method to convert the corner type * of the card to an icon and a method to convert the object type of the card to an icon as well. The class uses * Unicode characters to represent the icons of the cards and the objects. In addition, the class - * includes ASCI escape codes to set the color of the printed cards and the printed text. + * includes ASCII escape codes to set the color of the printed cards and the printed text. *

By the playing phase, players also have the possibility to interact with the chat and use the keyword to interact * with the game, for example, type β€œSH” to show the hand of the player. * @author Jie @@ -109,7 +108,7 @@ public class TextUI extends View{ * Unicode characters used to represent the icon PLANT */ private static final String PLANT = "\uD83C\uDF3F"; - /** + /** * Unicode characters used to represent the icon FUNGI */ private static final String FUNGI = "\uD83C\uDF44"; @@ -125,9 +124,9 @@ public class TextUI extends View{ * Unicode characters used to represent the icon INKWELL */ private static final String INKWELL = "\uD83C\uDF6F"; -/** - * Unicode characters used to represent the icon MANUSCRIPT - */ + /** + * Unicode characters used to represent the icon MANUSCRIPT + */ private static final String MANUSCRIPT = "\uD83D\uDCDC"; /** * Unicode characters used to represent the icon β€œX”; @@ -168,6 +167,7 @@ public class TextUI extends View{ /** * Constructor of the class TextUI + * @implSpec NON-BLOCKING */ public TextUI() { super(); @@ -191,6 +191,13 @@ public void launch() { boolean isEnd = false; while (!isEnd) { // TODO think about a better way to handle the flow of the game switch (Status) { + case WELCOME -> { + switch (currentEvent) { + case CREATE_GAME_FAILURE -> askCreateGame(); + case JOIN_GAME_FAILURE -> askJoinGame(); + case RECONNECT_GAME_FAILURE -> askReconnectGame(); + } + } case PREPARATION -> { if(currentEvent.equals(Event.SELECT_STARTER_CARD_SIDE)) { requestSelectStarterCardSide(startCard); @@ -222,6 +229,7 @@ public void launch() { * RMI connection, the method asks the player to insert the server URL. * The method uses the {@link IsValid} class to check the validity of the IP address and the port number entered by * the player. + * @implSpec BLOCKING-NON-INTERRUPTIBLE */ @Override public void chooseConnection() { @@ -240,68 +248,71 @@ public void chooseConnection() { switch (connectionChoice) { case 1: { // Player chooses socket connection // Ask the player to insert the server IP - out.println("Insert the server IP:"); // Ask the player to insert the server IP + out.println("Insert the server IP: "); // Ask the player to insert the server IP String serverIP = in.nextLine(); // Read the player's input while (!isValid.isIpValid(serverIP)) { // Check if the IP address is valid - out.println("Invalid IP, please try again"); // Print an error message + out.println("Invalid IP, please try again!"); // Print an error message serverIP = in.nextLine(); // Ask the player to re-enter the IP address } // Ask the player to insert the server port - out.println("Insert the server port:"); // Ask the player to insert the server port + out.println("Insert the server port: "); // Ask the player to insert the server port int port = getInputInt(); // Read the player's input while (!isValid.isPortValid(port)) { // Check if the port number is valid - out.println("Invalid port, please try again"); // Print an error message + out.println("Invalid port, please try again!"); // Print an error message port = getInputInt(); // Ask the player to re-enter the port number } try { setSocketClient(serverIP, port); // Set the socket client isConnected = true; // Set the connection status to true - } catch (IOException e) { // If an I/O error occurs - Thread.currentThread().interrupt(); // Interrupt the current thread - // TODO Should probably log this + } catch (ConnectionSetupFailedException e) { + // Do nothing, the connection status is already false. + // We will print a connection failed message later and loop again } break; } case 2: { // Player chooses RMI connection // Ask the player to insert the server IP - out.println("Insert the server IP"); // Ask the player to insert the server URL - // TODO Should ask the player to insert the server URL in a specific format + out.println("Insert the server IP: "); // Ask the player to insert the server IP String serverIP = in.nextLine(); // Read the player's input while (!isValid.isIpValid(serverIP)) { // Check if the IP is valid - out.println("Invalid IP, please try again"); // Print an error message + out.println("Invalid IP, please try again!"); // Print an error message serverIP = in.nextLine(); // Ask the player to re-enter the IP } // Ask the player to insert the server port - out.println("Insert the server port:"); // Ask the player to insert the server port + out.println("Insert the server port: "); // Ask the player to insert the server port int port = getInputInt(); // Read the player's input while (!isValid.isPortValid(port)) { // Check if the port number is valid - out.println("Invalid port, please try again"); // Print an error message + out.println("Invalid port, please try again!"); // Print an error message port = getInputInt(); // Ask the player to re-enter the port number } - // TODO mettere exception come - setRMIClient(serverIP, port); // Set the RMI client - isConnected = true; // Set the connection status to true + try { + setRMIClient(serverIP, port); // Set the RMI client + isConnected = true; // Set the connection status to true + } catch (ConnectionSetupFailedException e) { + // Do nothing, the connection status is already false. + // We will print a connection failed message later and loop again + } break; } default: { // If the player's input is not one of the valid options - out.println("Invalid input, please select 1 or 2"); + out.println("Invalid input, please select 1 or 2!"); continue; // Continue here to avoid a printing connection failed message } } // We have now attempted to establish a connection, but it may have failed if (!isConnected) { // If the connection is not established - out.println("Connection failed, please try again"); // Print an error message + out.println("Connection failed, you are free to try again!"); // Print an error message } } while (!isConnected); // Keep looping until the connection is established } @@ -309,31 +320,32 @@ public void chooseConnection() { /** * Method that sets the socket client with the server IP and the server port entered by the player and attempts to * establish the connection between the client and the server. - * + * @implSpec NON-BLOCKING * @param serverIP the server IP entered by the player * @param port the server port entered by the player - * @throws IOException if an I/O error occurs */ @Override - public void setSocketClient(String serverIP, int port) throws IOException { + public void setSocketClient(String serverIP, int port) throws ConnectionSetupFailedException { super.setSocketClient(serverIP, port); } /** * Method that sets the RMI client with the server URL entered by the player and attempts to establish the * connection between the client and the server. - * + * @implSpec NON-BLOCKING * @param serverURL the server URL entered by the player * @see View#setSocketClient(String, int) */ @Override - public void setRMIClient(String serverURL, int port) { + public void setRMIClient(String serverURL, int port) throws ConnectionSetupFailedException { super.setRMIClient(serverURL, port); // see the method in the superclass } + //-------------------Title------------------- /** * Method that prints the welcome message and link to the game rules. + * @implSpec NON-BLOCKING */ @Override public void showWelcome() { @@ -345,8 +357,9 @@ public void showWelcome() { β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ ═════╝ β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•šβ•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•šβ•β•β•β•β•β•β•"""); - out.println("Game rule:https://it.boardgamearena.com/link?url=https%3A%2F%2Fcdn.1j1ju.com%2Fmedias%2Fa7%2Fd7%2F66-codex-naturalis-rulebook.pdf&id=9212"); + out.println("Game rule:https://t.ly/ZtnYH"); } + //-------------------Game mode------------------- /** @@ -461,7 +474,7 @@ public void askReconnectGame() { /** * Once the player receives the NewGameConfirmationMessage from the server, the method is called by processMessage * to store the gameID, the nickname of the player who created the game, and add it in the list of players. - * + * @implSpec NON-BLOCKING * @param gameID the game ID returned by the server after the confirmation of the new game * @param recipientNickname the nickname of the player who asked to create the new game */ @@ -476,6 +489,7 @@ public void updateNewGameConfirm(int gameID, String recipientNickname) { /** * Once the player receives the LobbyPlayerList message from the server, the method is called by * processMessage, to update the player's list in the Lobby phase and print the player's list updated. + * @implSpec NON-BLOCKING * @param players the list updated of players in the game. */ @Override @@ -487,6 +501,7 @@ public void updatePlayerList(ArrayList players) { /** * The Method used to update the player's board and public info when the player disconnects from the game after the * placement of the card. + * @implSpec NON-BLOCKING * @param playerNickname the nickname of the player whose board should be updated with the rollback * @param removedCard the ID of the card that should be removed from the board and the public info of the player * @param playerPoints the points of the player after the rollback @@ -541,6 +556,7 @@ public void updateRollback(String playerNickname, int removedCard, int playerPoi /** * After receiving the GameStarted message from the server, the method is called to set up the view of the player * and initialize the data and the boards of the players. + * @implSpec NON-BLOCKING */ @Override public void setUpPlayersData() { @@ -551,12 +567,14 @@ public void setUpPlayersData() { boards.put(player, new BoardView(new int[]{80, 80, 80, 80}, new String[160][160])); } } + /** * Once the player receives the MatchStatus message from the server, the method is called by processMessage to * update the match status of the player, and print the message to notify the player of the current match status. * And if the match status is TERMINATING, the method is called to show the points of all players in the game. * One time the match status is PLAYING, the method is called to start the readInputThread to get the input from * the player when it is not the player's turn. + * @implSpec NON-BLOCKING * @param matchStatus the current match status received from the server */ @Override @@ -601,7 +619,8 @@ public void requestSelectStarterCardSide(int ID) { /** * Once received the ConfirmedStarterCardSideSelectionMessage from the server, the method is called by processMessage to - * update the view of the player and print the message to notify the player that the starter card is selected + * update the view of the player and print the message to notify the player that the starter card is selected. + * @implSpec NON-BLOCKING * @param colour the colour of the player in the game. * @param cardID the ID of the starter card selected by the player and received from the server. * @param isUp indicates the side of the card selected by the player to be placed. @@ -631,6 +650,7 @@ public void updateConfirmStarterCard(int colour, int cardID, boolean isUp, Array * processMessage to request the player to select the secret objective card they want to use. The player will be * able to see the front and back side of the card and select the card they want to use. Also, the player will be * able to see the common objective cards and three cards received from the server with this message. + * @implSpec NON-BLOCKING * @param secrets the secret objective cards received from the server and assigned to the player. * @param common the common objective cards of the game received from the server. * @param hand the three cards received from the server and should be stored in the player's hand. @@ -652,6 +672,7 @@ public void setCardsReceived(ArrayList secrets, ArrayList comm /** * Method that save the ID of the starter card received from the server. + * @implSpec NON-BLOCKING * @param cardId the ID of the starter card received from the server. */ @Override @@ -685,6 +706,7 @@ public void requestSelectSecretObjectiveCard() { /** * Once received the SecretObjCardConfirmationMessage from the server, the method is called by processMessage to * update the view of the player and print the message to notify the player that the secret objective card is selected + * @implSpec NON-BLOCKING * @param chosenSecretObjectiveCard the ID of the secret objective card selected by the player. */ @Override @@ -699,7 +721,7 @@ public void updateConfirmSelectedSecretCard(int chosenSecretObjectiveCard) { /** * This method is called by processMessage to update the all data of the players in the game when the game enters * the playing phase or when the player reconnects to the game. - * + * @implSpec NON-BLOCKING * @param playerNicknames the nicknames of the players in the game. * @param playerConnected the connection status of the players in the game. * @param playerColours the colours assigned to the players in the game. @@ -873,6 +895,7 @@ public void updatePlayerData(ArrayList playerNicknames, ArrayList hand) { * Once the player receives the DeckSizeUpdateMessage from the server, the method is called by processMessage to * update the deck size and the current visible resource cards and gold cards in the game. Also, the method prints * the message to notify the player the situation of the deck after this turn. + * @implSpec NON-BLOCKING * @param resourceDeckSize the size of the resource deck in the game. * @param goldDeckSize the size of the gold deck in the game. * @param currentResourceCards the current visible resource cards in the game that the player can draw. @@ -1239,6 +1266,7 @@ public void updateDeck(int resourceDeckSize, int goldDeckSize, int[]currentResou * Method called when player opens chat from getInput method. * Enables the user to select a player to chat with, or chat with all players. * The user can also exit the chat. + * @implSpec BLOCKING-BUT-RAN-FROM-RIT */ @Override public void startChatting() { @@ -1316,6 +1344,8 @@ else if (messageContent.equals("EXIT")) { // Abort sending message /** * Method to print out the chat history of the player. + * @implSpec NON-BLOCKING + * @param chatHistory the chat history of the player. */ @Override public void showChatHistory(List chatHistory){ @@ -1336,6 +1366,7 @@ else if(chat.getRecipientNickname().equals(thisPlayerNickname) || chat.isMultica /** * Method used to update the chat history of the player when a new message is received, add the message to the chat * history and print the chat history if the player is in the chat mode. + * @implSpec NON-BLOCKING * @param recipientString the nickname of the recipient of the message. * @param senderNickname the nickname of the sender of the message. * @param content the content of the message. @@ -1351,8 +1382,10 @@ public void updateChat(String recipientString, String senderNickname, String con } //-------------------Show Methods------------------- + /** * Print the deck size and the current visible resource cards and gold cards in the game. + * @implSpec NON-BLOCKING */ @Override public void showDeck() { @@ -1368,6 +1401,7 @@ public void showDeck() { /** * Print the list of commands that the player can use in the service mode. + * @implSpec NON-BLOCKING */ @Override public void showHelpInfo() { @@ -1387,11 +1421,13 @@ public void showHelpInfo() { SGO: to see the game order. SID: to see the game ID. SCD: to see the deck size and the current visible cards in the game. - + """); } + /** * Print list of the players in the game. + * @implSpec NON-BLOCKING */ public void showPlayerInGame() { out.println("The players in the game are: " + players); @@ -1399,6 +1435,7 @@ public void showPlayerInGame() { /** * Print the board view and the resources in the field of the given player. + * @implSpec NON-BLOCKING * @param playerNickname the nickname of the player whose field should be printed. */ public void showPlayersField(String playerNickname) { @@ -1408,6 +1445,7 @@ public void showPlayersField(String playerNickname) { /** * Print the resources in the field of the player. + * @implSpec NON-BLOCKING * @param playerNickname the nickname of the player whose resources should be printed. */ @Override @@ -1424,7 +1462,7 @@ public void showPointsAndResource(String playerNickname) { /** * Print the zone of the board where the player placed his cards and the available positions for the next * placement. - * + * @implSpec NON-BLOCKING * @param nickname the nickname of the player, the owner of the board that should be printed. */ private void showBoard(String nickname) { @@ -1441,8 +1479,10 @@ private void showBoard(String nickname) { out.println(); } } + /** * Print the cards in the hand of the player. + * @implSpec NON-BLOCKING */ @Override public void showHand() { @@ -1457,6 +1497,7 @@ public void showHand() { /** * Print the objective cards. + * @implSpec NON-BLOCKING * @param ObjCards the ID of the objective cards that should be printed. */ private void showObjectiveCards(ArrayList ObjCards) { @@ -1469,6 +1510,9 @@ private void showObjectiveCards(ArrayList ObjCards) { /** * Print a card based on the ID of the card and the side of the card. + * @implSpec NON-BLOCKING + * @param ID the ID of the card. + * @param isUp the side of the card. */ @Override public void showCard(int ID, boolean isUp) { @@ -1489,6 +1533,7 @@ public void showCard(int ID, boolean isUp) { /** * Print at the end of the match the final points of the players, the secret objective card of the players, and the * points gained from the objective card. Also, the method prints the winners of the match. + * @implSpec NON-BLOCKING * @param players the nicknames of the players in the game. * @param points the final points of the players in the game. * @param secrets the secret objective card of the players. @@ -1498,7 +1543,7 @@ public void showCard(int ID, boolean isUp) { @Override public void showMatchWinners(ArrayList players, ArrayList points, ArrayList secrets, ArrayList pointsGainedFromObj, ArrayList winners) { - currentEvent = Event.TERMINATED; + Status = Event.TERMINATED; out.println("The match is ended !!!"); out.println("The winners of the match are: "+winners); out.println("The final points of the players are following:"); @@ -1516,8 +1561,10 @@ public void showMatchWinners(ArrayList players, ArrayList point } //-------------------Card Factory------------------- + /** * Search the card description based on the ID of the card. + * @implSpec NON-BLOCKING * @param ID the ID of the card. * @return the card description. */ @@ -1537,6 +1584,7 @@ private NonObjCardFactory searchNonObjCardById(int ID) { /** * Set the image of the card based on the card description, the view of the card in TUI. Store the image of the card * in the hashmap with the ID of the card as the key. + * @implSpec NON-BLOCKING * @return hashmap with the ID of the card as the key and the image of the card as the value. */ private HashMap> setImg() { @@ -1730,7 +1778,7 @@ private HashMap> setImg() { } case "AllSpecial": { // description of the three objects that should be count in the field. - description = "INSKELL+QUILL+MANUSCRIPT"; + description = "INKWELL+QUILL+MANUSCRIPT"; paddingDescription = 26 - description.length(); paddingIcon = 26 - 3 * icon("INKWELL").length(); paddingPoint = 26 - (value + " POINTS" + strategy).length(); @@ -1752,9 +1800,9 @@ private HashMap> setImg() { /** * Use this method to set the color of the card based on the kingdom of the card. - * + * @implSpec NON-BLOCKING * @param kingdom the kingdom of the card. - * @return the string of the color in ASCI escape code. + * @return the string of the color in ASCII escape code. */ private static String ColourCard(String kingdom) { String colour = ""; @@ -1771,7 +1819,7 @@ private static String ColourCard(String kingdom) { /** * The Method used to convert the integer array of the condition count of the card to a string of icons, using the * Unicode characters and added it in one string. - * + * @implSpec NON-BLOCKING * @param conditionCount the integer array of the requirement counts of the card. * @return the string of icons which contains the icons of the requirements of the card. */ @@ -1791,7 +1839,7 @@ private static String iconArray(int[] conditionCount) { /** * Method used to convert the corner type of the card to an icon, using the Unicode characters. - * + * @implSpec NON-BLOCKING * @param type the corner type of the card. * @return the icon of the corner type of the card. */ @@ -1814,6 +1862,7 @@ private static String icon(String type) { /** * Method used to convert the type of the resource/object that stored in the array of requirements of the card or * in the array of the permanent resources of the card to an icon, using the Unicode characters. + * @implSpec NON-BLOCKING */ private static String iconArrayElement(int type) { String icon; @@ -1832,6 +1881,7 @@ private static String iconArrayElement(int type) { /** * Method used to convert the colour of the card to an icon, using the Unicode characters. + * @implSpec NON-BLOCKING */ private static String iconCard(String type) { String icon; @@ -1847,6 +1897,7 @@ private static String iconCard(String type) { /** * Colour the string based on the integer received. + * @implSpec NON-BLOCKING * @param colour indicates the colour of the string. * @return the string β€œcolour” coloured. */ @@ -1873,12 +1924,13 @@ public String convertToColour(int colour) { } } } + //-------------------utilities------------------- /** * Used method to update the dimensions of the player's board view after placing a card on the board. * The method is called by the {@link View#updateAfterPlacedCard} method. - * + * @implSpec NON-BLOCKING * @param posX the x coordinate of the card placed. * @param posY the y coordinate of the card placed. * @param limits the array of the limits contains the maximum x and y and the minimum x and y updated. @@ -1889,56 +1941,55 @@ private void updateBoardViewLimits(int posX, int posY, int[] limits) { limits[2] = Math.max(limits[2], posY + 1); limits[3] = Math.min(limits[3], posY - 1); } + /** * Used method to handle the failure messages received from the server and to ask the user to try again. + * @implSpec NON-BLOCKING * @param event the event that failed. * @param reason the reason of the failure. */ @Override - public void handleFailureCase(Event event,String reason){ - out.println(reason); + public void handleFailureCase(Event event, String reason){ switch (event){ - case CHOOSE_CONNECTION -> { // Connection failure - out.println("Please try again:"); - chooseConnection(); - } - case CREATE_GAME-> { // Create game failure - out.println("Please try again:"); - askCreateGame(); + case CREATE_GAME-> { // Should never happen! + out.println("Please try again! Reason: " + reason); + currentEvent = Event.CREATE_GAME_FAILURE; } - case JOIN_GAME-> { // Join game failure - out.println("Please try again:"); - askJoinGame(); + case JOIN_GAME-> { + out.println("Please try again! Reason: " + reason); + currentEvent = Event.JOIN_GAME_FAILURE; } - case RECONNECT_GAME -> { // Reconnect game failure - out.println("Please try again:"); - askReconnectGame(); + case RECONNECT_GAME -> { + out.println("Please try again! Reason: " + reason); + currentEvent = Event.RECONNECT_GAME_FAILURE; } - case PLACE_CARD_FAILURE -> { // Place card failure - out.println("Please try again:"); + case PLACE_CARD_FAILURE -> { + out.println("Please try again! Reason: " + reason); currentEvent = Event.PLACE_CARD; } - case DRAW_CARD_FAILURE -> { // Draw card failure - out.println("Please try again:"); + case DRAW_CARD_FAILURE -> { + out.println("Please try again! Reason: " + reason); currentEvent = Event.DRAW_CARD; } - case SELECT_SECRET_OBJ_CARD_FAILURE -> { // Select secret objective card failure - out.println("Please try again:"); + case SELECT_SECRET_OBJ_CARD_FAILURE -> { + out.println("Please try again! Reason: " + reason); currentEvent = Event.SELECTED_SECRET_OBJ_CARD; } - case SELECT_STARTER_CARD_SIDE_FAILURE -> { // Select starter card side failure - out.println("Please try again:"); + case SELECT_STARTER_CARD_SIDE_FAILURE -> { + out.println("Please try again! Reason: " + reason); currentEvent = Event.SELECT_STARTER_CARD_SIDE; } - case CHAT_ERROR -> { // Chat error - out.println("!The last message was not sent!"); - ChatMessage error = new ChatMessage("NOTICE",thisPlayerNickname, false,"The last message was not sent! "+reason); + case CHAT_ERROR -> { + out.println("The last message was not sent! Reason: " + reason); + ChatMessage error = new ChatMessage("NOTICE", thisPlayerNickname, false,"The last message was not sent! " + reason); chatHistory.add(error); } } } + /** * Used method to print the message to notify the player when is necessary. + * @implSpec NON-BLOCKING * @param event the type of the event that should be handled. * @param nickname the nickname of the player will be used in the message. */ @@ -1970,22 +2021,6 @@ public void handleEvent(Event event,String nickname) { } } - /** - * Use this method to clear the console screen. - */ - private void clearCMD() { //TODO: ADDED THIS METHOD TO CLEAR THE SCREEN - try { - if (System.getProperty("os.name").contains("Windows")) - new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor(); - else - Runtime.getRuntime().exec("clear"); - } catch (IOException | InterruptedException e) { - Thread.currentThread().interrupt(); - } - System.out.print("\033[H\033[2J"); - System.out.flush(); - } - /** * The Method used to get the input from the user and handle the commands that the user can use to interact with the * game in the service mode. @@ -1993,7 +2028,7 @@ private void clearCMD() { //TODO: ADDED THIS METHOD TO CLEAR THE SCREEN */ private synchronized String getInput() { String input = ""; - if (!currentEvent.equals(Event.TERMINATED)) { + if (!Status.equals(Event.TERMINATED)) { input= in.nextLine(); } switch (input) { @@ -2002,7 +2037,7 @@ private synchronized String getInput() { case "Chat" -> startChatting(); case "SP" -> showPlayerInGame(); case "SGS" -> out.println("The match status is: " + Status); - case "SR" -> out.println("Game rule:https://it.boardgamearena.com/link?url=https%3A%2F%2Fcdn.1j1ju.com%2Fmedias%2Fa7%2Fd7%2F66-codex-naturalis-rulebook.pdf&id=9212"); + case "SR" -> out.println("Game rule:https://t.ly/ZtnYH"); case "SH" -> showHand(); case "SCO" -> showObjectiveCards(commonObjCards); case "SSO" -> showCard(secretObjCardSelected, true); @@ -2049,11 +2084,10 @@ private int getInputInt() { } } } -} - - - - - + // TODO implementare metodo + public void nodeDisconnected(){} + // TODO implementare metodo + public void nodeReconnected(){} +} diff --git a/src/main/java/it/polimi/ingsw/am32/controller/GamesManager.java b/src/main/java/it/polimi/ingsw/am32/controller/GamesManager.java index 4c43fe4a..6030fcb5 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/GamesManager.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/GamesManager.java @@ -114,9 +114,9 @@ public synchronized GameController createGame(String creatorName, int playerCoun * @throws GameNotFoundException If no game with the given code is found * @throws FullLobbyException If the lobby of the game is full * @throws GameAlreadyStartedException If the game has already started - * @throws DuplicateNicknameException If the player with the given nickname is already in the game + * @throws CTRDuplicateNicknameException If the player with the given nickname is already in the game */ - public synchronized GameController accessGame(String nickname, int gameCode, NodeInterface node) throws GameNotFoundException, FullLobbyException, GameAlreadyStartedException, DuplicateNicknameException { + public synchronized GameController accessGame(String nickname, int gameCode, NodeInterface node) throws GameNotFoundException, FullLobbyException, GameAlreadyStartedException, CTRDuplicateNicknameException { logger.debug("Received request to access game. Nickname: {}, game code: {}, node: {}", nickname, gameCode, node); if(nickname == null || nickname.isBlank()) { throw new CriticalFailureException("Nickname cannot be null or empty"); @@ -149,6 +149,8 @@ public synchronized GameController accessGame(String nickname, int gameCode, Nod } } catch (VirtualViewNotFoundException e) { // Player was added, but his virtual view could not be found throw new CriticalFailureException("VirtualViewNotFoundException when player joined the game"); + } catch (DuplicateNicknameException e) { // Player is not added to the game as he has a duplicate nickname + throw new CTRDuplicateNicknameException("Player with nickname " + nickname + " is already in the game"); } if (game.getGameSize() == game.getLobbyPlayerCount()) { // Lobby is now full @@ -169,12 +171,13 @@ public synchronized GameController accessGame(String nickname, int gameCode, Nod * @param node The server node associated with the given player * @return The GameController of the game with the given code * @throws GameAlreadyEndedException If the game has already ended - * @throws PlayerNotFoundException If the player with the given nickname is not found in the game + * @throws CTRPlayerNotFoundException If the player with the given nickname is not found in the game * @throws GameNotFoundException If no game with the given code is found * @throws PlayerAlreadyConnectedException If the player with the given nickname is already connected to the game + * @throws GameNotYetStartedException If the game has not yet started */ public synchronized GameController reconnectToGame(String nickname, int gameCode, NodeInterface node) throws - GameAlreadyEndedException, PlayerNotFoundException, GameNotFoundException, PlayerAlreadyConnectedException, + GameAlreadyEndedException, CTRPlayerNotFoundException, GameNotFoundException, PlayerAlreadyConnectedException, GameNotYetStartedException { logger.debug("Received request to reconnect to game. Nickname: {}, game code: {}, node: {}", nickname, gameCode, node); @@ -206,6 +209,8 @@ public synchronized GameController reconnectToGame(String nickname, int gameCode } } catch (VirtualViewNotFoundException e) { throw new CriticalFailureException("VirtualViewNotFoundException when player reconnected to the game"); + } catch (PlayerNotFoundException e) { + throw new CTRPlayerNotFoundException("Player with nickname " + nickname + " not found in the game"); } return game; diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRDuplicateNicknameException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRDuplicateNicknameException.java new file mode 100644 index 00000000..3ad2c33c --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRDuplicateNicknameException.java @@ -0,0 +1,20 @@ +package it.polimi.ingsw.am32.controller.exceptions; + +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + +/** + * This exception is thrown when a player tries to join a lobby with a nickname that is already in use. + */ +public class CTRDuplicateNicknameException extends LobbyMessageException { + /** + * Creates a new CTRDuplicateNicknameException with the given message. + * @param message The message of the exception. + */ + public CTRDuplicateNicknameException(String message) { + super( + LobbyMessageExceptionEnumeration.DUPLICATE_NICKNAME_EXCEPTION, + message + ); + } +} diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRPlayerNotFoundException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRPlayerNotFoundException.java new file mode 100644 index 00000000..0996e42b --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/CTRPlayerNotFoundException.java @@ -0,0 +1,20 @@ +package it.polimi.ingsw.am32.controller.exceptions; + +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + +/** + * This exception is thrown when a player tries to join a lobby with a nickname that is already in use. + */ +public class CTRPlayerNotFoundException extends LobbyMessageException { + /** + * Creates a new CTRPlayerNotFoundException with the given message. + * @param message The message of the exception. + */ + public CTRPlayerNotFoundException(String message) { + super( + LobbyMessageExceptionEnumeration.PLAYER_NOT_FOUND_EXCEPTION, + message + ); + } +} diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/FullLobbyException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/FullLobbyException.java index f139da40..95dd25b5 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/FullLobbyException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/FullLobbyException.java @@ -1,13 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** * This exception is thrown when a player tries to join a full lobby. */ -public class FullLobbyException extends Exception { +public class FullLobbyException extends LobbyMessageException { /** - * Constructor for the exception. - * - * @param message The message to be displayed when the exception is thrown + * Creates a new FullLobbyException with the given message. + * @param message The message of the exception. */ - public FullLobbyException(String message) { super(message); } + public FullLobbyException(String message) { + super( + LobbyMessageExceptionEnumeration.FULL_LOBBY_EXCEPTION, + message + ); + } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyEndedException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyEndedException.java index 127b32a6..a31422f1 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyEndedException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyEndedException.java @@ -1,15 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** * This exception is thrown when a game is already ended and a player tries to join it. */ -public class GameAlreadyEndedException extends Exception { +public class GameAlreadyEndedException extends LobbyMessageException { /** - * Constructor - * - * @param message The message to be shown + * Creates a new GameAlreadyEndedException with the given message. + * @param message The message of the exception. */ public GameAlreadyEndedException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.GAME_ALREADY_ENDED_EXCEPTION, + message + ); } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyStartedException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyStartedException.java index af034783..c1222a65 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyStartedException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameAlreadyStartedException.java @@ -1,15 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** * This exception is thrown when a game is already started and a player tries to join it. */ -public class GameAlreadyStartedException extends Exception { +public class GameAlreadyStartedException extends LobbyMessageException { /** - * Constructor - * - * @param message The message to be shown + * Creates a new GameAlreadyStartedException with the given message. + * @param message The message of the exception. */ public GameAlreadyStartedException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.GAME_ALREADY_STARTED_EXCEPTION, + message + ); } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotFoundException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotFoundException.java index 3234039c..b4efcae8 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotFoundException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotFoundException.java @@ -1,17 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** * This class represents an exception that is thrown when no game is found. - * It extends the Exception class, meaning it's a checked exception. - * Checked exceptions need to be declared in a method or constructor's throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary. */ -public class GameNotFoundException extends Exception { +public class GameNotFoundException extends LobbyMessageException { /** - * Constructs a new NoGameFoundException with the specified detail message. - * - * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. + * Constructs a new NoGameFoundException with the given message. + * @param message The message of the exception. */ public GameNotFoundException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.GAME_NOT_FOUND_EXCEPTION, + message + ); } -} \ No newline at end of file +} diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotYetStartedException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotYetStartedException.java index f30a8b8c..b2d5b1f2 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotYetStartedException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/GameNotYetStartedException.java @@ -1,17 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** - * This class represents a custom exception that is thrown when a game operation is attempted - * before the game has officially started. It extends the Exception class, thereby inheriting - * its methods and can be used in a try-catch block. + * This exception is thrown when a player tries to connect to a game that has not yet started. */ -public class GameNotYetStartedException extends Exception { +public class GameNotYetStartedException extends LobbyMessageException { /** - * Constructor for the GameNotYetStartedException class. - * - * @param message The detail message which is saved for later retrieval by the Throwable.getMessage() method. + * Creates a new GameNotYetStartedException with the given message. + * @param message The message of the exception. */ public GameNotYetStartedException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.GAME_NOT_YET_STARTED_EXCEPTION, + message + ); } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/InvalidPlayerNumberException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/InvalidPlayerNumberException.java index 0b7d081f..9f28c3b2 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/InvalidPlayerNumberException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/InvalidPlayerNumberException.java @@ -1,15 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** * This exception is thrown when the number of players in a game is invalid. */ -public class InvalidPlayerNumberException extends Exception { +public class InvalidPlayerNumberException extends LobbyMessageException { /** * Creates a new InvalidPlayerNumberException with the given message. - * - * @param message The message of the exception + * @param message The message of the exception. */ public InvalidPlayerNumberException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.INVALID_PLAYER_NUMBER_EXCEPTION, + message + ); } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/PlayerAlreadyConnectedException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/PlayerAlreadyConnectedException.java index 5eba39f3..b8e41ac7 100644 --- a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/PlayerAlreadyConnectedException.java +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/PlayerAlreadyConnectedException.java @@ -1,15 +1,20 @@ package it.polimi.ingsw.am32.controller.exceptions; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration; + /** - * PlayerAlreadyConnectedException is thrown when a player tries to connect to the server but he is already connected + * This exception is thrown when a player is already connected but tries to connect again somehow. */ -public class PlayerAlreadyConnectedException extends Exception { +public class PlayerAlreadyConnectedException extends LobbyMessageException { /** - * Constructor - * - * @param message the message to be shown + * Creates a new PlayerAlreadyConnectedException with the given message. + * @param message The message of the exception. */ public PlayerAlreadyConnectedException(String message) { - super(message); + super( + LobbyMessageExceptionEnumeration.PLAYER_ALREADY_CONNECTED_EXCEPTION, + message + ); } } diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageException.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageException.java new file mode 100644 index 00000000..3ea0f3b0 --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageException.java @@ -0,0 +1,32 @@ +package it.polimi.ingsw.am32.controller.exceptions.abstraction; + +/** + * The LobbyMessageException class represents an exception that can be thrown during + * the elaboration of a generic Lobby-Message. + * It contains the type of the exception and a message associated with it. + * @see it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration + */ +public abstract class LobbyMessageException extends Exception { + /** + * The type of LobbyMessageException. + */ + private final LobbyMessageExceptionEnumeration exceptionType; + + /** + * Constructor for the LobbyMessageException class. + * @param exceptionType The type of LobbyMessageException. + * @param message The message associated with the exception. + */ + public LobbyMessageException(LobbyMessageExceptionEnumeration exceptionType, String message) { + super(message); + this.exceptionType = exceptionType; + } + + /** + * Gets the enumeration type of the exception. + * @return The enumeration type of the exception. + */ + public LobbyMessageExceptionEnumeration getExceptionType() { + return exceptionType; + } +} diff --git a/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageExceptionEnumeration.java b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageExceptionEnumeration.java new file mode 100644 index 00000000..06ab0e79 --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/controller/exceptions/abstraction/LobbyMessageExceptionEnumeration.java @@ -0,0 +1,40 @@ +package it.polimi.ingsw.am32.controller.exceptions.abstraction; + +/** + * The LobbyMessageExceptionEnumeration enum represents the different exceptions that can be thrown during + * the elaboration of a generic Lobby-Message. + * Each exception is associated with a specific integer value. + * @value The integer value associated with each exception. + */ +public enum LobbyMessageExceptionEnumeration { + INVALID_PLAYER_NUMBER_EXCEPTION(0), + GAME_ALREADY_STARTED_EXCEPTION(1), + FULL_LOBBY_EXCEPTION(2), + DUPLICATE_NICKNAME_EXCEPTION(3), + GAME_NOT_FOUND_EXCEPTION(4), + GAME_ALREADY_ENDED_EXCEPTION(5), + PLAYER_NOT_FOUND_EXCEPTION(6), + PLAYER_ALREADY_CONNECTED_EXCEPTION(7), + GAME_NOT_YET_STARTED_EXCEPTION(8); + + /** + * The integer value associated with each state. + */ + private final int value; + + /** + * Constructor for the MatchStatus enum. + * @param value The integer value associated with the state. + */ + LobbyMessageExceptionEnumeration(int value) { + this.value = value; + } + + /** + * Gets the integer value associated with the state. + * @return The integer value of the state. + */ + public int getValue() { + return value; + } +} diff --git a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/AccessGameMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/AccessGameMessage.java index 761fab40..d9e3a076 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/AccessGameMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/AccessGameMessage.java @@ -2,10 +2,10 @@ import it.polimi.ingsw.am32.controller.GameController; import it.polimi.ingsw.am32.controller.GamesManager; +import it.polimi.ingsw.am32.controller.exceptions.CTRDuplicateNicknameException; import it.polimi.ingsw.am32.controller.exceptions.FullLobbyException; import it.polimi.ingsw.am32.controller.exceptions.GameAlreadyStartedException; import it.polimi.ingsw.am32.controller.exceptions.GameNotFoundException; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; import it.polimi.ingsw.am32.network.ServerNode.NodeInterface; /** @@ -33,11 +33,12 @@ public AccessGameMessage(int matchId, String senderNickname) { * @return the game controller of the game the player wants to join * @throws GameAlreadyStartedException if the game has already started * @throws FullLobbyException if the lobby is full - * @throws DuplicateNicknameException if the nickname is already in use * @throws GameNotFoundException if the game was not found + * @throws CTRDuplicateNicknameException if the nickname is already in use */ @Override - public GameController elaborateMessage(NodeInterface nodeInterface) throws GameAlreadyStartedException, FullLobbyException, DuplicateNicknameException, GameNotFoundException { + public GameController elaborateMessage(NodeInterface nodeInterface) throws GameAlreadyStartedException, + FullLobbyException, GameNotFoundException, CTRDuplicateNicknameException { return GamesManager.getInstance().accessGame(senderNickname, matchId, nodeInterface); } diff --git a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSLobbyMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSLobbyMessage.java index af5f8738..5bbef5d3 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSLobbyMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSLobbyMessage.java @@ -1,9 +1,7 @@ package it.polimi.ingsw.am32.message.ClientToServer; import it.polimi.ingsw.am32.controller.GameController; -import it.polimi.ingsw.am32.controller.exceptions.*; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; import it.polimi.ingsw.am32.network.ServerNode.NodeInterface; import java.io.Serializable; @@ -13,9 +11,6 @@ * It contains a single method to elaborate the message */ public interface CtoSLobbyMessage extends Serializable { - GameController elaborateMessage(NodeInterface nodeInterface) throws InvalidPlayerNumberException, - GameAlreadyStartedException, FullLobbyException, DuplicateNicknameException, GameNotFoundException, - GameAlreadyEndedException, PlayerNotFoundException, PlayerAlreadyConnectedException, - GameNotYetStartedException; + GameController elaborateMessage(NodeInterface nodeInterface) throws LobbyMessageException; String toString(); // Used for debugging purposes } diff --git a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSMessage.java index 5b6565de..dab4e356 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/CtoSMessage.java @@ -1,7 +1,6 @@ package it.polimi.ingsw.am32.message.ClientToServer; import it.polimi.ingsw.am32.controller.GameController; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import java.io.Serializable; @@ -13,7 +12,6 @@ public interface CtoSMessage extends Serializable { /** * Elaborates the message with the specified game controller. - * * @param gameController The game controller with which the message should be elaborated */ void elaborateMessage(GameController gameController); diff --git a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/ReconnectGameMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/ReconnectGameMessage.java index 7f9818b3..1621709d 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/ReconnectGameMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/ReconnectGameMessage.java @@ -2,11 +2,7 @@ import it.polimi.ingsw.am32.controller.GameController; import it.polimi.ingsw.am32.controller.GamesManager; -import it.polimi.ingsw.am32.controller.exceptions.GameAlreadyEndedException; -import it.polimi.ingsw.am32.controller.exceptions.GameNotFoundException; -import it.polimi.ingsw.am32.controller.exceptions.GameNotYetStartedException; -import it.polimi.ingsw.am32.controller.exceptions.PlayerAlreadyConnectedException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; +import it.polimi.ingsw.am32.controller.exceptions.*; import it.polimi.ingsw.am32.network.ServerNode.NodeInterface; public class ReconnectGameMessage implements CtoSLobbyMessage { @@ -20,8 +16,7 @@ public ReconnectGameMessage(String senderNickname, int matchId) { @Override public GameController elaborateMessage(NodeInterface nodeInterface) throws GameAlreadyEndedException, - PlayerNotFoundException, GameNotFoundException, PlayerAlreadyConnectedException, GameNotYetStartedException - { + GameNotFoundException, PlayerAlreadyConnectedException, GameNotYetStartedException, CTRPlayerNotFoundException { return GamesManager.getInstance().reconnectToGame(senderNickname, matchId, nodeInterface); } diff --git a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/RequestPlayerFieldMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/RequestPlayerFieldMessage.java index f4f710b8..b35d0de4 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/RequestPlayerFieldMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ClientToServer/RequestPlayerFieldMessage.java @@ -1,7 +1,6 @@ package it.polimi.ingsw.am32.message.ClientToServer; import it.polimi.ingsw.am32.controller.GameController; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; /** * This class is used to manage the message sent by the client when he wants to see the field of another player. diff --git a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ErrorMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ErrorMessage.java index cc1b5871..2f46f289 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ErrorMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ErrorMessage.java @@ -5,15 +5,17 @@ public class ErrorMessage implements StoCMessage{ private final String message; private final String recipientNickname; + private final int errorType; - public ErrorMessage(String message, String recipientNickname) { + public ErrorMessage(String message, String recipientNickname, int errorType) { this.message = message; this.recipientNickname = recipientNickname; + this.errorType = errorType; } @Override public void processMessage(View view) { - view.handleFailureCase(view.getEvent(),message); + view.handleFailureCase(view.getEvent(), message); } @Override @@ -26,6 +28,7 @@ public String toString() { return "ErrorMessage:{" + "message='" + message + '\'' + ", recipientNickname='" + recipientNickname + '\'' + + ", errorType=" + errorType + '}'; } } diff --git a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/InvalidInboundChatMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/InvalidInboundChatMessage.java index 02e84711..e01ae854 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/InvalidInboundChatMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/InvalidInboundChatMessage.java @@ -1,6 +1,5 @@ package it.polimi.ingsw.am32.message.ServerToClient; - import it.polimi.ingsw.am32.client.Event; import it.polimi.ingsw.am32.client.View; diff --git a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/PlaceCardConfirmationMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/PlaceCardConfirmationMessage.java index 2516e47b..5c9a5c42 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/PlaceCardConfirmationMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/PlaceCardConfirmationMessage.java @@ -1,6 +1,5 @@ package it.polimi.ingsw.am32.message.ServerToClient; -import it.polimi.ingsw.am32.client.Event; import it.polimi.ingsw.am32.client.View; import java.util.ArrayList; diff --git a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ResponseGameStatusFailedMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ResponseGameStatusFailedMessage.java deleted file mode 100644 index 1fc2a9e3..00000000 --- a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/ResponseGameStatusFailedMessage.java +++ /dev/null @@ -1,4 +0,0 @@ -package it.polimi.ingsw.am32.message.ServerToClient; - -public class ResponseGameStatusFailedMessage { -} diff --git a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/StoCMessage.java b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/StoCMessage.java index 128440c6..42bed70d 100644 --- a/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/StoCMessage.java +++ b/src/main/java/it/polimi/ingsw/am32/message/ServerToClient/StoCMessage.java @@ -11,10 +11,8 @@ public interface StoCMessage extends Serializable { /** * Delivers the message to the specified virtual view. - * - * */ void processMessage(View view); - String getRecipientNickname(); // Method needed for submitVirtualViewMessage method in Gamecontroller; GameController needs to know who to send message to + String getRecipientNickname(); // Method needed for submitVirtualViewMessage method in Gamecontroller; GameController needs to know who to send message to. String toString(); // Used for debugging purposes } diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptor.java b/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptor.java index 2a53ce56..ae16147b 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptor.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptor.java @@ -1,10 +1,8 @@ package it.polimi.ingsw.am32.network.ClientAcceptor; import it.polimi.ingsw.am32.controller.GameController; -import it.polimi.ingsw.am32.controller.exceptions.*; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; import it.polimi.ingsw.am32.message.ClientToServer.CtoSLobbyMessage; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import it.polimi.ingsw.am32.network.ClientNode.RMIClientNodeInt; import it.polimi.ingsw.am32.network.GameTuple; import it.polimi.ingsw.am32.network.ServerNode.RMIServerNode; @@ -22,10 +20,9 @@ public RMIClientAcceptor() throws RemoteException {} // TODO export stuff @Override - public GameTuple uploadToServer(RMIClientNodeInt node, CtoSLobbyMessage message) throws RemoteException, - GameAlreadyStartedException, FullLobbyException, InvalidPlayerNumberException, DuplicateNicknameException, - GameNotFoundException, GameAlreadyEndedException, PlayerNotFoundException, PlayerAlreadyConnectedException, - GameNotYetStartedException { + public GameTuple uploadToServer(RMIClientNodeInt node, CtoSLobbyMessage message) + throws RemoteException, LobbyMessageException + { logger.info("Received a CtoSLobbyMessage from a RMI client: {}", message.toString()); @@ -34,9 +31,8 @@ public GameTuple uploadToServer(RMIClientNodeInt node, CtoSLobbyMessage message) GameController gameController = null; try { gameController = message.elaborateMessage(rmiServerNode); - } catch (DuplicateNicknameException | InvalidPlayerNumberException | GameAlreadyStartedException | - GameNotYetStartedException | FullLobbyException | GameNotFoundException | GameAlreadyEndedException | - PlayerNotFoundException | PlayerAlreadyConnectedException e) { + } catch (LobbyMessageException e) { + // TODO: Handle the exception, send ErrorMessage to the client instead rmiServerNode.destroy(); logger.error("GameController access failed: {}", e.getMessage()); throw e; diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptorInt.java b/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptorInt.java index 031fe52d..bff7a719 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptorInt.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientAcceptor/RMIClientAcceptorInt.java @@ -1,9 +1,7 @@ package it.polimi.ingsw.am32.network.ClientAcceptor; -import it.polimi.ingsw.am32.controller.exceptions.*; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; import it.polimi.ingsw.am32.message.ClientToServer.CtoSLobbyMessage; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import it.polimi.ingsw.am32.network.ClientNode.RMIClientNodeInt; import it.polimi.ingsw.am32.network.GameTuple; @@ -11,8 +9,6 @@ import java.rmi.RemoteException; public interface RMIClientAcceptorInt extends Remote { - GameTuple uploadToServer(RMIClientNodeInt node, CtoSLobbyMessage message) throws RemoteException, - GameAlreadyStartedException, FullLobbyException, InvalidPlayerNumberException, DuplicateNicknameException, - GameNotFoundException, GameAlreadyEndedException, PlayerNotFoundException, PlayerAlreadyConnectedException, - GameNotYetStartedException; + GameTuple uploadToServer(RMIClientNodeInt node, CtoSLobbyMessage message) + throws RemoteException, LobbyMessageException; } diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientNodeInterface.java b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientNodeInterface.java index eaa22dea..0f64dc71 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientNodeInterface.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientNodeInterface.java @@ -4,8 +4,6 @@ import it.polimi.ingsw.am32.message.ClientToServer.CtoSMessage; import it.polimi.ingsw.am32.network.exceptions.UploadFailureException; -import java.io.IOException; - public interface ClientNodeInterface { void uploadToServer(CtoSMessage message) throws UploadFailureException; void uploadToServer(CtoSLobbyMessage message) throws UploadFailureException; diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientPingTask.java b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientPingTask.java index e58bd9f6..ebd5b3a9 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientPingTask.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/ClientPingTask.java @@ -8,4 +8,4 @@ public class ClientPingTask extends TimerTask { public void run() { node.pongTimeOverdue(); } -} \ No newline at end of file +} diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNode.java b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNode.java index 2ea5c00e..90054b57 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNode.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNode.java @@ -1,14 +1,12 @@ package it.polimi.ingsw.am32.network.ClientNode; import it.polimi.ingsw.am32.client.View; -import it.polimi.ingsw.am32.controller.exceptions.*; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; import it.polimi.ingsw.am32.message.ClientToServer.CtoSLobbyMessage; import it.polimi.ingsw.am32.message.ClientToServer.CtoSMessage; import it.polimi.ingsw.am32.message.ClientToServer.PingMessage; import it.polimi.ingsw.am32.message.ServerToClient.PongMessage; import it.polimi.ingsw.am32.message.ServerToClient.StoCMessage; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import it.polimi.ingsw.am32.network.ClientAcceptor.RMIClientAcceptorInt; import it.polimi.ingsw.am32.network.GameTuple; import it.polimi.ingsw.am32.network.exceptions.NodeClosedException; @@ -85,7 +83,7 @@ public void uploadToServer(CtoSMessage message) throws UploadFailureException { logger.info("Message sent. Type: CtoSMessage: {}", message); } catch (NodeClosedException e) { // TODO gestire eccezioni throw new RuntimeException(e); - } catch (PlayerNotFoundException | RemoteException e) { + } catch (RemoteException e) { throw new RuntimeException(e); } } @@ -114,10 +112,8 @@ public void uploadToServer(CtoSLobbyMessage message) throws UploadFailureExcepti } catch (RemoteException e) { // TODO come gestisco queste exception?? throw new RuntimeException(e); - } catch (GameAlreadyStartedException | FullLobbyException | InvalidPlayerNumberException | - DuplicateNicknameException | GameNotFoundException | GameAlreadyEndedException | - PlayerNotFoundException | PlayerAlreadyConnectedException | GameNotYetStartedException e) { - + } catch (LobbyMessageException e) { + // TODO: Handle exception correctly // view.failureCtoSLobby } } diff --git a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNodeInt.java b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNodeInt.java index 8e75a845..b5efec5c 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNodeInt.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ClientNode/RMIClientNodeInt.java @@ -6,6 +6,5 @@ import java.rmi.RemoteException; public interface RMIClientNodeInt extends Remote { - void uploadStoC(StoCMessage message) throws RemoteException; } diff --git a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/NodeInterface.java b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/NodeInterface.java index 533d30f0..8ef6f7e4 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/NodeInterface.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/NodeInterface.java @@ -1,13 +1,10 @@ package it.polimi.ingsw.am32.network.ServerNode; - import it.polimi.ingsw.am32.message.ServerToClient.StoCMessage; import it.polimi.ingsw.am32.network.exceptions.UploadFailureException; public interface NodeInterface { void uploadToClient(StoCMessage message) throws UploadFailureException; - void pingTimeOverdue(); - void resetTimeCounter(); -} \ No newline at end of file +} diff --git a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/RMIServerNodeInt.java b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/RMIServerNodeInt.java index ac9236a0..0d597ccd 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/RMIServerNodeInt.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/RMIServerNodeInt.java @@ -1,12 +1,11 @@ package it.polimi.ingsw.am32.network.ServerNode; import it.polimi.ingsw.am32.message.ClientToServer.CtoSMessage; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import it.polimi.ingsw.am32.network.exceptions.NodeClosedException; import java.rmi.Remote; import java.rmi.RemoteException; public interface RMIServerNodeInt extends Remote { - void uploadCtoS(CtoSMessage message) throws RemoteException, PlayerNotFoundException, NodeClosedException; + void uploadCtoS(CtoSMessage message) throws RemoteException, NodeClosedException; } diff --git a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/SKServerNode.java b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/SKServerNode.java index 1df4ea4f..55fd3ea7 100644 --- a/src/main/java/it/polimi/ingsw/am32/network/ServerNode/SKServerNode.java +++ b/src/main/java/it/polimi/ingsw/am32/network/ServerNode/SKServerNode.java @@ -1,15 +1,14 @@ package it.polimi.ingsw.am32.network.ServerNode; +import it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageException; +import it.polimi.ingsw.am32.network.exceptions.ErrorMessageCode; import it.polimi.ingsw.am32.utilities.Configuration; import it.polimi.ingsw.am32.controller.GameController; -import it.polimi.ingsw.am32.controller.exceptions.*; import it.polimi.ingsw.am32.message.ClientToServer.CtoSLobbyMessage; import it.polimi.ingsw.am32.message.ClientToServer.CtoSMessage; import it.polimi.ingsw.am32.message.ClientToServer.PingMessage; import it.polimi.ingsw.am32.message.ServerToClient.ErrorMessage; import it.polimi.ingsw.am32.message.ServerToClient.PongMessage; -import it.polimi.ingsw.am32.model.exceptions.DuplicateNicknameException; -import it.polimi.ingsw.am32.model.exceptions.PlayerNotFoundException; import it.polimi.ingsw.am32.network.exceptions.NodeClosedException; import it.polimi.ingsw.am32.network.exceptions.UninitializedException; import it.polimi.ingsw.am32.network.exceptions.UploadFailureException; @@ -169,7 +168,11 @@ private void listenForIncomingMessages() throws IOException, ClassNotFoundExcept else if (message instanceof CtoSMessage) { if (gameController == null) { // It should never happen that the gameController hasn't yet been assigned when a CtoSMessage is received try { - uploadToClient(new ErrorMessage("Error: StoCMessage was sent before StoCLobbyMessage", "PLAYER")); + uploadToClient(new ErrorMessage( + "StoCMessage was sent before StoCLobbyMessage", + "PLAYER", + ErrorMessageCode.STOCMESSAGE_SENT_BEFORE_STOCLOBBYMESSAGE.getCode() + )); logger.info("StoCMessage received before StoCLobbyMessage. Sending ErrorMessage to client"); } catch (UploadFailureException e) { logger.error("StoCMessage received before StoCLobbyMessage. Failed to send ErrorMessage to client"); @@ -189,7 +192,11 @@ else if (message instanceof CtoSMessage) { else if (message instanceof CtoSLobbyMessage) { if (gameController != null) { // It should never happen that the gameController has already been assigned when a CtoSLobbyMessage is received try { - uploadToClient(new ErrorMessage("Error: StoCLobbyMessage was sent when the game has already been chosen", "PLAYER")); + uploadToClient(new ErrorMessage( + "StoCLobbyMessage was sent when the game has already been chosen", + "PLAYER", + ErrorMessageCode.STOCLOBBYMESSAGE_SENT_BUT_GAMECONTROLLER_ALREADY_PRESENT.getCode() + )); logger.info("StoCLobbyMessage received when gameController already assigned. Sending ErrorMessage to client"); } catch (UploadFailureException e) { logger.error("StoCLobbyMessage received when gameController already assigned. Failed to send ErrorMessage to client"); @@ -207,70 +214,17 @@ else if (message instanceof CtoSLobbyMessage) { gameController.getTimer().scheduleAtFixedRate(serverPingTask, 0, Configuration.getInstance().getPingTimeInterval()); logger.info("Elaborated CtoSLobbyMessage received: {}", message.toString()); - } catch (InvalidPlayerNumberException e) { + } catch (LobbyMessageException e) { try { - uploadToClient(new ErrorMessage("Error: invalid player number", "PLAYER")); + uploadToClient(new ErrorMessage( + e.getMessage(), + "PLAYER", + e.getExceptionType().getValue() + )); logger.info("Invalid player number. Sending ErrorMessage to client"); } catch (UploadFailureException ex) { logger.error("Invalid player number. Failed to send ErrorMessage to client"); } - } catch (GameAlreadyStartedException e) { - try { - uploadToClient(new ErrorMessage("Error: Game already started", "PLAYER")); - logger.info("Game already started. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Game already started. Failed to send ErrorMessage to client"); - } - } catch (FullLobbyException e) { - try { - uploadToClient(new ErrorMessage("Error: Lobby already is full", "PLAYER")); - logger.info("Lobby is already full. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Lobby is already full. Failed to send ErrorMessage to client"); - } - } catch (DuplicateNicknameException e) { - try { - uploadToClient(new ErrorMessage("Error: Player nickname already in use", "PLAYER")); - logger.info("Player nickname already in use. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Player nickname already in use. Failed to send ErrorMessage to client"); - } - } catch (GameNotFoundException e) { - try { - uploadToClient(new ErrorMessage("Error: Game not found", "PLAYER")); - logger.info("Game not found. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Game not found. Failed to send ErrorMessage to client"); - } - } catch (GameAlreadyEndedException e) { - try { - uploadToClient(new ErrorMessage("Error: Game already ended", "PLAYER")); - logger.info("Game already ended. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Game already ended. Failed to send ErrorMessage to client"); - } - } catch (GameNotYetStartedException e) { - try { - uploadToClient(new ErrorMessage("Error: Game has not yet started, cannot reconnect now." + - " Try accessing the game instead", "PLAYER")); - logger.info("Game not yet started. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Game not yet started. Failed to send ErrorMessage to client"); - } - } catch (PlayerNotFoundException e) { - try { - uploadToClient(new ErrorMessage("Error: Player not found", "PLAYER")); - logger.info("Player not found. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Player not found. Failed to send ErrorMessage to client"); - } - } catch (PlayerAlreadyConnectedException e) { - try { - uploadToClient(new ErrorMessage("Error: Player already connected", "PLAYER")); - logger.info("Player already connected. Sending ErrorMessage to client"); - } catch (UploadFailureException ex) { - logger.error("Player already connected. Failed to send ErrorMessage to client"); - } } catch (Exception e) { logger.fatal("Error while elaborating CtoSLobbyMessage: ", e); throw e; @@ -278,7 +232,11 @@ else if (message instanceof CtoSLobbyMessage) { } else { // Unknown message type received try { - uploadToClient(new ErrorMessage("Error: message type not recognized", "PLAYER")); + uploadToClient(new ErrorMessage( + "Message type not recognized", + "PLAYER", + ErrorMessageCode.MESSAGE_TYPE_NOT_RECOGNIZED.getCode() + )); logger.info("Message type not recognized. Sending ErrorMessage to client"); } catch (UploadFailureException e) { logger.error("Message type not recognized. Failed to send ErrorMessage to client"); diff --git a/src/main/java/it/polimi/ingsw/am32/network/exceptions/ConnectionSetupFailedException.java b/src/main/java/it/polimi/ingsw/am32/network/exceptions/ConnectionSetupFailedException.java new file mode 100644 index 00000000..0d16d0ba --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/network/exceptions/ConnectionSetupFailedException.java @@ -0,0 +1,3 @@ +package it.polimi.ingsw.am32.network.exceptions; + +public class ConnectionSetupFailedException extends Throwable {} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/am32/network/exceptions/ErrorMessageCode.java b/src/main/java/it/polimi/ingsw/am32/network/exceptions/ErrorMessageCode.java new file mode 100644 index 00000000..c8eed5f5 --- /dev/null +++ b/src/main/java/it/polimi/ingsw/am32/network/exceptions/ErrorMessageCode.java @@ -0,0 +1,34 @@ +package it.polimi.ingsw.am32.network.exceptions; + +/** + * Enumerates the error message codes. + * The error message codes are used to identify the type of error that occurred. + * @see it.polimi.ingsw.am32.controller.exceptions.abstraction.LobbyMessageExceptionEnumeration + * @see it.polimi.ingsw.am32.message.ServerToClient.ErrorMessage + */ +public enum ErrorMessageCode { + STOCMESSAGE_SENT_BEFORE_STOCLOBBYMESSAGE(128), + STOCLOBBYMESSAGE_SENT_BUT_GAMECONTROLLER_ALREADY_PRESENT(127), + MESSAGE_TYPE_NOT_RECOGNIZED(126); + + /** + * The code associated with the error type. + */ + private final int code; + + /** + * Constructor for the error type. + * @param code The code associated with the error type. + */ + ErrorMessageCode(int code) { + this.code = code; + } + + /** + * Get the code associated with the error type. + * @return The code associated with the error type. + */ + public int getCode() { + return code; + } +} diff --git a/src/main/java/it/polimi/ingsw/am32/utilities/IsValid.java b/src/main/java/it/polimi/ingsw/am32/utilities/IsValid.java index 70a785cb..902bba4b 100644 --- a/src/main/java/it/polimi/ingsw/am32/utilities/IsValid.java +++ b/src/main/java/it/polimi/ingsw/am32/utilities/IsValid.java @@ -1,5 +1,9 @@ package it.polimi.ingsw.am32.utilities; +/** + * This class provides methods to check if an IP address and a port number are valid. + * Used to validate the IP address and port number provided by the user. + */ public class IsValid { /** * This method checks if the provided IP address is valid. diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 7aeb17c1..11e8d793 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -14,6 +14,7 @@ exports it.polimi.ingsw.am32.network.ClientAcceptor to java.rmi; exports it.polimi.ingsw.am32.network to java.rmi; exports it.polimi.ingsw.am32.model.exceptions to java.rmi; + exports it.polimi.ingsw.am32.controller.exceptions.abstraction to java.rmi; exports it.polimi.ingsw.am32.controller to java.rmi; exports it.polimi.ingsw.am32.controller.exceptions to java.rmi; exports it.polimi.ingsw.am32.network.exceptions to java.rmi; diff --git a/src/main/resources/.configureBeforePackaging.log4j2.xml b/src/main/resources/.configureBeforePackaging.log4j2.xml new file mode 100644 index 00000000..8a1247e8 --- /dev/null +++ b/src/main/resources/.configureBeforePackaging.log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/test/java/it/polimi/ingsw/am32/model/match/MatchSimulationTest.java b/src/test/java/it/polimi/ingsw/am32/model/match/MatchSimulationTest.java index 72613eec..b09e8042 100644 --- a/src/test/java/it/polimi/ingsw/am32/model/match/MatchSimulationTest.java +++ b/src/test/java/it/polimi/ingsw/am32/model/match/MatchSimulationTest.java @@ -12,7 +12,6 @@ import static org.junit.jupiter.api.Assertions.*; -import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.TestTemplate;