From e28e7bab6da9c97ed893c7c474b9df0cd6e58a56 Mon Sep 17 00:00:00 2001 From: MatteoPellegrino05 Date: Mon, 18 May 2026 18:52:29 +0200 Subject: [PATCH] Add: complete JavaDoc for networking, heartbeat, totem flow and game events --- .../gc14/Controller/ClientController.java | 19 ++- .../ingsw/gc14/Controller/GameController.java | 28 +++- .../gc14/Model/Cards/Building/EffectType.java | 33 ++++- .../Model/Cards/TribeCards/CharacterType.java | 31 ++++- .../Model/Cards/TribeCards/EventType.java | 23 +++- .../java/it/polimi/ingsw/gc14/Model/Game.java | 89 +++++++++++-- .../gc14/Model/GamePackage/GameStages.java | 42 +++++- .../it/polimi/ingsw/gc14/Model/Totems.java | 29 +++- .../polimi/ingsw/gc14/Network/EventType.java | 66 +++++++-- .../it/polimi/ingsw/gc14/Network/IClient.java | 76 +++++++++-- .../ingsw/gc14/Network/NetworkEvent.java | 125 +++++++++++++----- .../Network/NetworkEvents/ApplyNextRound.java | 10 +- .../gc14/Network/NetworkEvents/EndedGame.java | 10 +- .../NetworkEvents/ReconnectPlayer.java | 43 ++++-- .../Network/NetworkEvents/TotemChoice.java | 57 ++++++-- .../gc14/Network/RMI/Client/RMIClient.java | 14 +- .../Network/RMI/Common/IClientCallback.java | 2 +- .../gc14/Network/RMI/Common/IGameServer.java | 93 +++++++++++-- .../gc14/Network/RMI/Server/RMIHeartbeat.java | 30 ++--- .../gc14/Network/RMI/Server/RMIServer.java | 92 ++++++++----- .../gc14/Network/TCP/Client/TCPClient.java | 10 +- .../Network/TCP/Server/ClientHandler.java | 18 ++- .../Network/TCP/Server/HeartbeatHandler.java | 67 +++++++++- .../it/polimi/ingsw/gc14/ServerLauncher.java | 74 +++++++++-- .../gc14/View/GUI/TotemFXMLController.java | 1 - .../it/polimi/ingsw/gc14/View/TUI/TUI.java | 7 + 26 files changed, 890 insertions(+), 199 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java index 70cc100..8e39e4a 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java +++ b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java @@ -26,6 +26,9 @@ public class ClientController { /** Network client (either TCP or RMI) */ private IClient client; + /** + * The username of the client associated with this event. + */ public String myUsername; @@ -65,6 +68,11 @@ public class ClientController { view.setModel(miniModel); } + /** + * Sets the username of the client associated with this event. + * + * @param username the username to set. + */ public void setMyUsername (String username) { this.myUsername=username; } @@ -170,7 +178,16 @@ public class ClientController { } } - //TODO + /** + * Handles the selection of a totem by the specified player. + * + *

If the player is not the current one, an error message is shown. + * Otherwise, the selected totem is retrieved from the available totems + * and the choice is forwarded to the client. + * + * @param playerUsername the username of the player making the choice. + * @param pos the position of the selected totem in the available totems list. + */ public void totemChoice(String playerUsername,int pos) { if(!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) view.showError("It's not your turn!"); diff --git a/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java b/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java index 0a5ade5..382b2f6 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java +++ b/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java @@ -30,7 +30,14 @@ public class GameController { */ public GameController() { } - //TODO + + /** + * Marks the player associated with the specified username as disconnected. + * + * @param username the username of the player who disconnected. + * @return {@code true} if the disconnection is handled successfully, + * {@code false} if no player with the specified username exists. + */ public boolean DisconnectedPlayer(String username) { Player player= model.getPlayerByUsername(username); @@ -38,7 +45,14 @@ public class GameController { return false; return model.DisconnectedPlayer(player); } - //TODO + + /** + * Marks the player associated with the specified username as reconnected. + * + * @param username the username of the player who reconnected. + * @return {@code true} if the reconnection is handled successfully, + * {@code false} if no player with the specified username exists. + */ public boolean ReconnectPlayer(String username) { Player player= model.getPlayerByUsername(username); @@ -46,6 +60,7 @@ public class GameController { return false; return model.ReconnectPlayer(player); } + /** * Returns the game model managed by this controller. * @@ -166,7 +181,14 @@ public class GameController { return model.SlotChoiceByIndex(model.getPlayerByUsername(playerUsername),pos); } - //TODO + /** + * Applies the totem choice made by the player associated with the specified username. + * + * @param playerUsername the username of the player making the choice. + * @param totem the name of the selected totem. + * @return {@code true} if the choice is handled successfully, + * {@code false} if no player with the specified username exists. + */ public boolean TotemChoice(String playerUsername,String totem) { Player player= model.getPlayerByUsername(playerUsername); if(player==null) diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/EffectType.java b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/EffectType.java index ed7ba06..6377ae2 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/EffectType.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/EffectType.java @@ -4,5 +4,34 @@ package it.polimi.ingsw.gc14.Model.Cards.Building; * Represents the possible effect types of building cards. */ public enum EffectType { - FINAL, CARD_SET, INVENTOR_PAIR, ON_EVENT, ON_END_TURN, ON_ROUND_END -} + + /** + * Effect applied during the final scoring phase. + */ + FINAL, + + /** + * Effect based on collecting a specific set of cards. + */ + CARD_SET, + + /** + * Effect based on pairs of Inventor cards. + */ + INVENTOR_PAIR, + + /** + * Effect triggered when an event card is resolved. + */ + ON_EVENT, + + /** + * Effect triggered at the end of a player's turn. + */ + ON_END_TURN, + + /** + * Effect triggered at the end of a round. + */ + ON_ROUND_END + } diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/CharacterType.java b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/CharacterType.java index 68f3962..f86db05 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/CharacterType.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/CharacterType.java @@ -4,5 +4,34 @@ package it.polimi.ingsw.gc14.Model.Cards.TribeCards; * Represents the different types of character cards available in the game. */ public enum CharacterType { - INVENTOR, BUILDER, GATHERER, ARTIST, SHAMAN, HUNTER + + /** + * Character card representing an Inventor. + */ + INVENTOR, + + /** + * Character card representing a Builder. + */ + BUILDER, + + /** + * Character card representing a Gatherer. + */ + GATHERER, + + /** + * Character card representing an Artist. + */ + ARTIST, + + /** + * Character card representing a Shaman. + */ + SHAMAN, + + /** + * Character card representing a Hunter. + */ + HUNTER } diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/EventType.java b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/EventType.java index 1b6720a..9752352 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/EventType.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/TribeCards/EventType.java @@ -4,5 +4,24 @@ package it.polimi.ingsw.gc14.Model.Cards.TribeCards; * Represents the different types of event cards available in the game. */ public enum EventType { - SUSTENANCE, SHAMANIC_RITUAL, CAVE_PAINTINGS, HUNT -} + + /** + * Event card representing Sustenance. + */ + SUSTENANCE, + + /** + * Event card representing the Shamanic Ritual. + */ + SHAMANIC_RITUAL, + + /** + * Event card representing Cave Paintings. + */ + CAVE_PAINTINGS, + + /** + * Event card representing the Hunt. + */ + HUNT + } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java index 7a56903..47ba0c1 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java @@ -29,11 +29,20 @@ import java.util.stream.Stream; */ public class Game implements Serializable { - + /** + * The final ranking of players at the end of the game. + */ private ArrayList playerStanding; + + /** + * Returns the final ranking of players. + * + * @return the list of players ordered according to their final standing. + */ public ArrayList getPlayerStanding() { return playerStanding; } + /** * Returns the list of players participating in the game. * @@ -42,16 +51,38 @@ public class Game implements Serializable { public List getPlayers() { return playersList; } - //TODO + + /** + * Returns the list of totems that have not yet been assigned to any player. + * + * @return the list of currently available totems. + */ public ListgetAvailableTotems() { List totems=new ArrayList<>(List.of(Totems.values())); playersList.forEach(player -> {if(player.totem!=null)totems.remove(player.totem);}); return totems; } - //TODO + + /** + * Queue containing the players who still have to choose their totem. + */ private Queue totemChoiceQueue = new LinkedList<>(); - //TODO + /** + * Assigns the selected totem to the specified player during the totem choice phase. + * + *

The choice is accepted only if the game is currently in the + * {@link GameStages#TOTEM_CHOICE} stage, the player is the current one, + * and the selected totem is still available. + * + *

After a valid choice, the method advances to the next player in the queue. + * If all players have completed the selection, the game moves to the slot choice phase. + * Disconnected players are automatically assigned a random available totem. + * + * @param player the player making the totem choice. + * @param totem the selected totem. + * @return {@code true} if the choice is applied successfully, {@code false} otherwise. + */ public boolean TotemChoice(Player player,Totems totem) { if(!currentState.getGameStage().equals(GameStages.TOTEM_CHOICE)) return false; @@ -87,9 +118,23 @@ public class Game implements Serializable { return true; } - //TODO + /** + * Map tracking the players who are currently disconnected. + */ public Map disconnetedPlayers = new HashMap<>(); - //TODO + + /** + * Marks the specified player as disconnected and updates the game flow accordingly. + * + *

If the player disconnects during the waiting phase, they are removed from + * the player list and from the totem choice queue. If the disconnected player is + * the current one, the game advances to the next suitable player or, during the + * totem choice phase, handles the remaining selection flow automatically. + * + * @param player the player who disconnected. + * @return {@code true} if the disconnection is handled successfully, + * {@code false} if the player was already marked as disconnected. + */ public boolean DisconnectedPlayer(Player player) { if(disconnetedPlayers.containsKey(player) && disconnetedPlayers.get(player)) @@ -121,7 +166,17 @@ public class Game implements Serializable { return true; } - //TODO + /** + * Marks the specified player as reconnected. + * + *

If the player reconnects during the slot choice phase, they are removed + * from the disconnected players map and reinserted into the order logic card + * when necessary. + * + * @param player the player who reconnected. + * @return {@code true} if the reconnection is handled successfully, + * {@code false} if the player was not previously marked as disconnected. + */ public boolean ReconnectPlayer(Player player) { if(!disconnetedPlayers.containsKey(player)) @@ -140,12 +195,14 @@ public class Game implements Serializable { return true; } - //Totem - //TODO + /** + * Clears the collection of disconnected players. + */ public void ClearDisconnected() { disconnetedPlayers.clear(); } + /** * Returns the current number of players participating in the game. * @return the current number of players. @@ -195,7 +252,12 @@ public class Game implements Serializable { * The board associated with this game. */ private Board board; - //TODO + + /** + * Returns the game board. + * + * @return the board associated with the game. + */ public Board getBoard() {return board;} /** @@ -925,6 +987,13 @@ public class Game implements Serializable { return true; } + /** + * Ends the game by forfeit and determines the final player standing. + * + *

The player who is still connected is declared the winner and placed + * in the first position of the final ranking. The remaining players are + * ordered by prestige value and, in case of a tie, by food value. + */ public void EndGameForFeit() { Player winner=playersList.stream().filter(x->!disconnetedPlayers.containsValue(x)||!disconnetedPlayers.get(x)).toList().get(0); currentState.GameStageUpdate(GameStages.ENDED); diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java b/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java index c0ba67e..fad51b1 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java @@ -4,5 +4,43 @@ package it.polimi.ingsw.gc14.Model.GamePackage; * Represents the possible stages of a game. */ public enum GameStages { - WAITING,TOTEM_CHOICE, SLOT_CHOICE, RES_ACTIONS, OPT_CARD_E, RES_EVENT, ENDING, ENDED -} + /** + * Stage in which the game is waiting for players to join. + */ + WAITING, + + /** + * Stage in which players choose their totems. + */ + TOTEM_CHOICE, + + /** + * Stage in which players select their action slots. + */ + SLOT_CHOICE, + + /** + * Stage in which the mandatory actions associated with the chosen slots are resolved. + */ + RES_ACTIONS, + + /** + * Stage in which an optional card effect can be resolved. + */ + OPT_CARD_E, + + /** + * Stage in which an event card is being resolved. + */ + RES_EVENT, + + /** + * Stage in which end-of-round or end-of-game operations are processed. + */ + ENDING, + + /** + * Stage indicating that the game has ended. + */ + ENDED + } diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Totems.java b/src/main/java/it/polimi/ingsw/gc14/Model/Totems.java index ea459e1..c15fbd1 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Totems.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Totems.java @@ -1,5 +1,32 @@ package it.polimi.ingsw.gc14.Model; +/** + * Represents the different totem colors available in the game. + */ public enum Totems { - YELLOW, BLUE, ORANGE, WHITE, PURPLE + + /** + * Yellow totem. + */ + YELLOW, + + /** + * Blue totem. + */ + BLUE, + + /** + * Orange totem. + */ + ORANGE, + + /** + * White totem. + */ + WHITE, + + /** + * Purple totem. + */ + PURPLE } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/EventType.java b/src/main/java/it/polimi/ingsw/gc14/Network/EventType.java index a1f8fe4..535e400 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/EventType.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/EventType.java @@ -5,16 +5,64 @@ package it.polimi.ingsw.gc14.Network; * client and server. */ public enum EventType { - ADD_PLAYER, + + /** + * Event used to add a player to the game. + */ + ADD_PLAYER, + + /** + * Event used to submit a player's totem choice. + */ TOTEM_CHOICE, - SLOT_CHOICE, - DRAW_UPPER_TRIBE, - DRAW_LOWER_TRIBE, - DRAW_UPPER_BUILD, - DRAW_LOWER_BUILD, + + /** + * Event used to submit a player's slot choice. + */ + SLOT_CHOICE, + + /** + * Event used to draw a tribe card from the upper card list. + */ + DRAW_UPPER_TRIBE, + + /** + * Event used to draw a tribe card from the lower card list. + */ + DRAW_LOWER_TRIBE, + + /** + * Event used to draw a building card from the upper card list. + */ + DRAW_UPPER_BUILD, + + /** + * Event used to draw a building card from the lower card list. + */ + DRAW_LOWER_BUILD, + + /** + * Event used to skip the current turn or optional action. + */ SKIP_TURN, - DISCONNECTED_PLAYER, - RECONNECT_PLAYER, + + /** + * Event used to notify that a player has disconnected. + */ + DISCONNECTED_PLAYER, + + /** + * Event used to notify that a player has reconnected. + */ + RECONNECT_PLAYER, + + /** + * Event used to apply the transition to the next round. + */ NEXT_ROUND, + + /** + * Event used to notify that the game has ended. + */ ENDED_GAME -} + } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/IClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/IClient.java index c633910..43704e2 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/IClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/IClient.java @@ -1,25 +1,73 @@ package it.polimi.ingsw.gc14.Network; -import it.polimi.ingsw.gc14.Network.NetworkEvents.*; - -import java.rmi.RemoteException; -import java.util.Objects; - +/** + * Defines the operations that a client can request during the game. + */ public interface IClient { - public boolean connect(String username,int preferredInt); - public void drawUpperTribeCard(String playerUsername, int pos) ; + /** + * Connects the client to the server using the specified username + * and preferred connection type. + * + * @param username the username chosen by the player. + * @param preferredInt the preferred connection type selected by the client. + * @return {@code true} if the connection is established successfully, + * {@code false} otherwise. + */ + boolean connect(String username, int preferredInt); - public void drawLowerTribeCard(String playerUsername,int pos) ; + /** + * Requests to draw a tribe card from the upper tribe card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card in the upper tribe card list. + */ + void drawUpperTribeCard(String playerUsername, int pos); - public void drawUpperBuildingCard(String playerUsername,int pos) ; + /** + * Requests to draw a tribe card from the lower tribe card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card in the lower tribe card list. + */ + void drawLowerTribeCard(String playerUsername, int pos); + /** + * Requests to draw a building card from the upper building card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card in the upper building card list. + */ + void drawUpperBuildingCard(String playerUsername, int pos); - public void drawLowerBuildingCard(String playerUsername,int pos) ; + /** + * Requests to draw a building card from the lower building card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card in the lower building card list. + */ + void drawLowerBuildingCard(String playerUsername, int pos); - public void skipTurn(String playerUsername); - + /** + * Requests to skip the current player's optional action. + * + * @param playerUsername the username of the player skipping the action. + */ + void skipTurn(String playerUsername); - public void slotChoice(String playerUsername,int pos) ; - public void totemChoice(String playerUsername,String totem) ; + /** + * Requests to assign the specified player to a slot. + * + * @param playerUsername the username of the player making the slot choice. + * @param pos the position of the selected slot. + */ + void slotChoice(String playerUsername, int pos); + + /** + * Requests to assign the selected totem to the specified player. + * + * @param playerUsername the username of the player making the totem choice. + * @param totem the name of the selected totem. + */ + void totemChoice(String playerUsername, String totem); } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvent.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvent.java index aeacecd..d5eecad 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvent.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvent.java @@ -11,59 +11,113 @@ import java.io.Serializable; import java.util.Map; /** - * Represents an event sent over the network + * Represents an event sent over the network. + * + *

A network event contains the information required to identify + * the requested action, determine whether it produced an error, + * and apply it either to the server-side {@link GameController} + * or to the client-side {@link MiniModel}. */ public abstract class NetworkEvent implements Serializable { - /** Username of the player requesting the event */ + + /** + * Username of the player requesting the event. + */ protected String username; /** - * @return the username of the player requesting the event + * Returns the username of the player requesting the event. + * + * @return the username associated with the event. */ public String getUsername() { return username; } - /** EventType of the event */ + /** + * Type of the network event. + */ protected EventType eventType; + /** + * Map associating each occupied slot with the corresponding player. + */ protected Map slotPlayerMap; + + /** + * Order logic card used to manage the player turn order. + */ protected OrderLogicCard orderLogicCard; + + /** + * Current state of the game associated with the event. + */ protected CurrentState currentState; + + /** + * Player directly involved in the event, when required. + */ protected Player player; - public void setData(Map slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState,Player player) { + /** + * Sets the game data associated with this network event. + * + * @param slotPlayerMap the map associating each slot with the player occupying it. + * @param orderLogicCard the order logic card used to manage turn order. + * @param currentState the current state of the game. + * @param player the player directly associated with the event. + */ + public void setData(Map slotPlayerMap, + OrderLogicCard orderLogicCard, + CurrentState currentState, + Player player) { this.slotPlayerMap = slotPlayerMap; this.orderLogicCard = orderLogicCard; this.currentState = currentState; this.player = player; } - /** - * @return the type of the event - */ - public EventType getEventType() {return eventType;} - /** Flag signaling whether the event could not be applied to the server model */ + /** + * Returns the type of this event. + * + * @return the event type. + */ + public EventType getEventType() { + return eventType; + } + + /** + * Flag indicating whether the event could not be applied successfully. + */ protected boolean isError; /** - * @return the flag signaling whether the event could be applied to the server model + * Returns whether the event represents an error. + * + * @return {@code true} if the event could not be applied successfully, + * {@code false} otherwise. */ - public boolean getIsError() {return isError;} + public boolean getIsError() { + return isError; + } /** - * Set the isError flag. - * @param isError the value to set + * Sets whether the event represents an error. + * + * @param isError {@code true} if the event could not be applied successfully, + * {@code false} otherwise. */ - public void setIsError(boolean isError) {this.isError = isError;} - + public void setIsError(boolean isError) { + this.isError = isError; + } /** - * Class constructor. - * Initializes all attributes. - * @param username the username of the player requesting the event - * @param eventType the type of the event - * @param isError the flag signaling if the event could be applied to the server model + * Constructs a network event. + * + * @param username the username of the player requesting the event. + * @param eventType the type of the event. + * @param isError {@code true} if the event represents an error, + * {@code false} otherwise. */ protected NetworkEvent(String username, EventType eventType, boolean isError) { this.username = username; @@ -71,26 +125,35 @@ public abstract class NetworkEvent implements Serializable { this.isError = isError; } - /** - * @return a string describing the name of the event and whether it is an error or not + * Returns a textual description of the event and its outcome. + * + * @return a string describing the event type and whether it represents an error. */ @Override public String toString() { - if(isError) { - return ("ERROR: action " + eventType.toString()); + if (isError) { + return "ERROR: action " + eventType; } else { - return ("ACTION: action " + eventType.toString()); + return "ACTION: action " + eventType; } } /** - * The method to apply the current event to the specified Game Controller. - * @param gameController the Game Controller on which to apply the event - * @return true if the event could be applied; false otherwise + * Applies this event to the specified server-side game controller. + * + * @param gameController the game controller on which the event must be applied. + * @return {@code true} if the event is applied successfully, + * {@code false} otherwise. */ public abstract boolean apply(GameController gameController); - //TODO + /** + * Applies this event to the specified client-side mini model. + * + * @param model the mini model on which the event must be applied. + * @return {@code true} if the event is applied successfully, + * {@code false} otherwise. + */ public abstract boolean apply(MiniModel model); -} +} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java index fe52676..901f529 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java @@ -20,7 +20,15 @@ import java.util.Map; public class ApplyNextRound extends NetworkEvent implements Serializable{ List players; - //TODO + + /** + * Constructs an event that updates the game state for the next round. + * + * @param slotPlayerMap the map associating each slot with the player occupying it. + * @param orderLogicCard the order logic card that determines the player order. + * @param currentState the current state of the game. + * @param players the list of players in the game. + */ public ApplyNextRound(Map slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, List players){ super("SERVER",EventType.NEXT_ROUND,false); this.slotPlayerMap = slotPlayerMap; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java index 6f9f950..d42cfed 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java @@ -21,7 +21,15 @@ import java.util.Map; public class EndedGame extends NetworkEvent implements Serializable{ ArrayList players; - //TODO + + /** + * Constructs an event containing the final game state. + * + * @param slotPlayerMap the map associating each slot with the player occupying it. + * @param orderLogicCard the order logic card that determines the player order. + * @param currentState the current state of the game. + * @param players the list of players at the end of the game. + */ public EndedGame(Map slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, ArrayList players){ super("SERVER",EventType.ENDED_GAME,false); this.slotPlayerMap = slotPlayerMap; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java index ffcca72..cf38d51 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java @@ -7,39 +7,54 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent; import java.io.Serializable; -//TODO -public class ReconnectPlayer extends NetworkEvent implements Serializable{ +/** + * Network event used to notify that a player has reconnected to the game. + */ +public class ReconnectPlayer extends NetworkEvent implements Serializable { /** - * Class constructor. - * Initializes all the attributes. - * @param username the name of the player requesting the event + * Constructs a reconnection event for the specified player. + * + * @param username the username of the player who reconnected. */ - public ReconnectPlayer(String username){ + public ReconnectPlayer(String username) { super(username, EventType.RECONNECT_PLAYER, false); } /** - * @param gameController the Game Controller on which to apply the event - * @return true if the player could skipTheTurn, false otherwise + * Applies the reconnection event to the server-side game controller. + * + * @param gameController the game controller on which to apply the event. + * @return {@code true} if the player reconnection is handled successfully, + * {@code false} otherwise. */ @Override - public boolean apply(GameController gameController){ + public boolean apply(GameController gameController) { return gameController.ReconnectPlayer(username); } - //TODO + /** + * Applies the reconnection update to the client-side mini model. + * + *

If the event does not represent an error, the player data, + * turn order, current game state, and slot assignments are updated. + * + * @param miniModel the mini model on which to apply the event. + * @return {@code true} if the update is applied successfully, + * {@code false} if the event represents an error. + */ @Override - public boolean apply(MiniModel miniModel){ - if(isError) + public boolean apply(MiniModel miniModel) { + if (isError) return false; - if(miniModel!=null) { + + if (miniModel != null) { miniModel.setPlayer(player); miniModel.setOrderLogicCard(orderLogicCard); miniModel.setCurrentState(currentState); miniModel.setSlotPlayerMap(slotPlayerMap); } + return true; } - } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java index e911423..04ace18 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java @@ -5,49 +5,78 @@ import it.polimi.ingsw.gc14.Model.MiniModel; import it.polimi.ingsw.gc14.Model.Totems; import it.polimi.ingsw.gc14.Network.EventType; import it.polimi.ingsw.gc14.Network.NetworkEvent; -import it.polimi.ingsw.gc14.View.IView; import java.io.Serializable; import java.util.List; /** - * NetworkEvent to select a slot where to place the player totem. + * Network event used to handle a player's totem choice. */ -public class TotemChoice extends NetworkEvent implements Serializable { +public class TotemChoice extends NetworkEvent implements Serializable { - /** Index of the card to draw */ + /** + * Name of the totem selected by the player. + */ private String totem; - private ListavailableTotems; + + /** + * List of totems still available after the choice has been processed. + */ + private List availableTotems; + + /** + * Sets the list of currently available totems. + * + * @param availableTotems the totems still available for selection. + */ public void setAvailableTotems(List availableTotems) { this.availableTotems = availableTotems; } - //TODO + + /** + * Constructs a totem choice event for the specified player. + * + * @param username the username of the player making the choice. + * @param totem the name of the selected totem. + */ public TotemChoice(String username, String totem) { super(username, EventType.TOTEM_CHOICE, false); this.totem = totem; } /** - * @param gameController the Game Controller on which to apply the event - * @return true if the player could draw the card, false otherwise + * Applies the totem choice event to the server-side game controller. + * + * @param gameController the game controller on which to apply the event. + * @return {@code true} if the totem choice is handled successfully, + * {@code false} otherwise. */ @Override public boolean apply(GameController gameController) { return gameController.TotemChoice(username, totem); } - //TODO + /** + * Applies the totem choice update to the client-side mini model. + * + *

If the event does not represent an error, the player data, + * turn order, current game state, slot assignments, and available + * totems are updated. + * + * @param miniModel the mini model on which to apply the event. + * @return {@code true} if the update is applied successfully, + * {@code false} if the event represents an error. + */ @Override - public boolean apply(MiniModel miniModel){ - if(isError) + public boolean apply(MiniModel miniModel) { + if (isError) return false; + miniModel.setPlayer(player); miniModel.setOrderLogicCard(orderLogicCard); miniModel.setCurrentState(currentState); miniModel.setSlotPlayerMap(slotPlayerMap); miniModel.setAvailableTotems(availableTotems); return true; - } - -} +} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java index 313e605..44f425a 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java @@ -1,18 +1,13 @@ package it.polimi.ingsw.gc14.Network.RMI.Client; -import java.net.InetAddress; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; -import java.util.Objects; import java.util.concurrent.*; import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Network.IClient; -import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvents.*; -import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback; import it.polimi.ingsw.gc14.Network.RMI.Common.IGameServer; -import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer; /** * Client RMI. Uses the methods exposed by the server RMI. @@ -34,7 +29,14 @@ public class RMIClient implements IClient { /** Scheduler that fires ping() every PING_INTERVAL_S seconds. */ private ScheduledExecutorService pingSender; - + /** + * Constructs an RMI client and initializes its connection parameters. + * + * @param controller the client controller associated with this RMI client. + * @param host the hostname or IP address of the RMI server. + * @param port the port used to connect to the RMI registry. + * @param myIP the IP address of the client. + */ public RMIClient(ClientController controller, String host, int port, String myIP) { this.controller = controller; this.host = host; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IClientCallback.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IClientCallback.java index c68c5b9..e09a065 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IClientCallback.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IClientCallback.java @@ -21,7 +21,7 @@ public interface IClientCallback extends Remote, Serializable { /** * Notifies the client that the game model has been initialized or updated. * - * @param model the current game model. + * @param miniModel the current mini model of the game. * @throws RemoteException if an RMI communication error occurs. */ void onGameInit(MiniModel miniModel) throws RemoteException; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IGameServer.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IGameServer.java index 64177ab..aef508d 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IGameServer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Common/IGameServer.java @@ -1,7 +1,5 @@ package it.polimi.ingsw.gc14.Network.RMI.Common; -import it.polimi.ingsw.gc14.Network.NetworkEvent; - import java.rmi.*; /** @@ -9,22 +7,89 @@ import java.rmi.*; */ public interface IGameServer extends Remote { + /** + * Adds a player to the game and registers the callback used by the server + * to notify the corresponding RMI client. + * + * @param username the username chosen by the player. + * @param preferredInt the preferred number of players for the game. + * @param callback the remote callback associated with the client. + * @return {@code true} if the player joins the game successfully, + * {@code false} otherwise. + * @throws RemoteException if an RMI communication error occurs. + */ boolean joinGame(String username, int preferredInt, IClientCallback callback) throws RemoteException; - boolean doEvent(NetworkEvent event) throws RemoteException; - - void drawUpperTribeCard(String playerUsername, int pos) throws RemoteException; - void drawLowerTribeCard(String playerUsername, int pos) throws RemoteException; - void drawUpperBuildingCard(String playerUsername, int pos) throws RemoteException; - void drawLowerBuildingCard(String playerUsername, int pos) throws RemoteException; - void skipTurn(String playerUsername) throws RemoteException; - void slotChoice(String playerUsername, int pos) throws RemoteException; - void totemChoice(String playerUsername, String totems) throws RemoteException; /** - * Heartbeat: called periodically by the client to signal it is still alive. - * Mirrors the PING/PONG mechanism used in the TCP heartbeat channel. + * Requests to draw a tribe card from the upper tribe card list. * - * @param username the username of the client sending the ping. + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card. + * @throws RemoteException if an RMI communication error occurs. + */ + void drawUpperTribeCard(String playerUsername, int pos) throws RemoteException; + + /** + * Requests to draw a tribe card from the lower tribe card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card. + * @throws RemoteException if an RMI communication error occurs. + */ + void drawLowerTribeCard(String playerUsername, int pos) throws RemoteException; + + /** + * Requests to draw a building card from the upper building card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card. + * @throws RemoteException if an RMI communication error occurs. + */ + void drawUpperBuildingCard(String playerUsername, int pos) throws RemoteException; + + /** + * Requests to draw a building card from the lower building card list. + * + * @param playerUsername the username of the player performing the action. + * @param pos the position of the selected card. + * @throws RemoteException if an RMI communication error occurs. + */ + void drawLowerBuildingCard(String playerUsername, int pos) throws RemoteException; + + /** + * Requests to skip the current player's optional action. + * + * @param playerUsername the username of the player skipping the action. + * @throws RemoteException if an RMI communication error occurs. + */ + void skipTurn(String playerUsername) throws RemoteException; + + /** + * Requests to assign the specified player to a slot. + * + * @param playerUsername the username of the player making the slot choice. + * @param pos the position of the selected slot. + * @throws RemoteException if an RMI communication error occurs. + */ + void slotChoice(String playerUsername, int pos) throws RemoteException; + + /** + * Requests to assign the selected totem to the specified player. + * + * @param playerUsername the username of the player making the totem choice. + * @param totems the name of the selected totem. + * @throws RemoteException if an RMI communication error occurs. + */ + void totemChoice(String playerUsername, String totems) throws RemoteException; + + /** + * Heartbeat method called periodically by the client to signal + * that it is still connected. + * + *

This method mirrors the PING/PONG mechanism used in the TCP + * heartbeat channel. + * + * @param username the username of the client sending the heartbeat ping. * @throws RemoteException if an RMI communication error occurs. */ void ping(String username) throws RemoteException; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIHeartbeat.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIHeartbeat.java index e9ee1f0..f164565 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIHeartbeat.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIHeartbeat.java @@ -1,7 +1,6 @@ package it.polimi.ingsw.gc14.Network.RMI.Server; import it.polimi.ingsw.gc14.LimitedMap; -import it.polimi.ingsw.gc14.Model.Game; import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvents.DisconnectedPlayer; @@ -15,14 +14,13 @@ import java.util.concurrent.*; * instead of reading raw bytes from a dedicated socket, it relies on {@link #receivePing()} * being called by {@link RMIServer#ping(String)} every time the client sends a ping. * - *

If no ping is received within {@value SILENCE_THRESHOLD_MS} ms the player is + *

If no ping is received within {@value SILENCE_THRESHOLD_MS} ms, the player is * considered disconnected and {@link #disconnect()} is invoked, which: *

*/ public class RMIHeartbeat { @@ -38,9 +36,6 @@ public class RMIHeartbeat { private volatile long lastPingTime = System.currentTimeMillis(); private volatile boolean running = true; - /** Reference to the current game model — needed to check whose turn it is. */ - private volatile Game game; - private final ScheduledExecutorService watchdog = Executors.newSingleThreadScheduledExecutor(r -> { Thread t = new Thread(r, "rmi-watchdog-" + username); @@ -48,6 +43,14 @@ public class RMIHeartbeat { return t; }); + /** + * Constructs an RMI heartbeat handler for the specified client. + * + * @param username the username of the client monitored by the heartbeat. + * @param playerList the map storing the connection status of the players. + * @param clients the collection of currently registered RMI clients. + * @param actionQueue the queue containing network events to be processed. + */ public RMIHeartbeat( String username, LimitedMap playerList, @@ -80,15 +83,12 @@ public class RMIHeartbeat { } /** - * Allows the server to keep the watchdog up-to-date with the current game - * model (needed to check whose turn it is on disconnect). + * Disconnects the monitored RMI client. + * + *

The heartbeat handler is stopped, the player is marked as offline, + * the associated RMI callback is removed, and a disconnection event is + * added to the action queue for server-side processing. */ - public void setGame(Game game) { - this.game = game; - } - - // ------------------------------------------------------------------------- - private void disconnect() { if (!running) return; running = false; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java index 1f8110b..5c10a9a 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java @@ -21,7 +21,12 @@ import java.rmi.*; /** - * Server RMI. Exposes a method to join the game and one to execute an event. + * RMI server responsible for handling remote client connections, + * receiving player actions, and propagating game updates. + * + *

The server manages player registration, reconnection handling, + * heartbeat monitoring, and the forwarding of client requests to the + * shared network event queue. */ public class RMIServer extends UnicastRemoteObject implements IGameServer { private String host; @@ -43,10 +48,26 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { private LimitedMap playerList; private boolean serverCrashed; + + /** + * Sets whether the server is recovering from a previous crash. + * + * @param serverCrashed {@code true} if the server is in crash-recovery mode, + */ public void setServerCrashed(boolean serverCrashed) { this.serverCrashed = serverCrashed; } + /** + * Constructs an RMI server with the required game and network components. + * + * @param controller the game controller used to manage the game logic. + * @param nPort the port used by the RMI registry. + * @param actionQueue the queue containing incoming network events. + * @param playerList the map storing the connection status of the players. + * @param host the hostname or IP address exposed by the RMI server. + * @throws RemoteException if the remote object cannot be exported. + */ public RMIServer(GameController controller, int nPort, BlockingQueue actionQueue, LimitedMap playerList, @@ -148,9 +169,13 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { // ------------------------------------------------------------------------- /** - * Notifies all clients of a new event. - * Also updates every watchdog with the latest model so disconnect logic - * knows whose turn it is. + * Notifies connected RMI clients of a new network event. + * + *

If the event does not represent an error, it is sent to all registered clients. + * If it represents an error, it is sent only to the client that requested the action. + * Communication errors are logged without interrupting the notification process. + * + * @param action the network event to send to the clients. */ public void notifyAll(NetworkEvent action){ for (Map.Entry entry : clients.entrySet()) { @@ -168,15 +193,15 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { } /** - * Notifies all clients of a new game model and keeps watchdogs up-to-date. - * Mirrors {@code TCPServer.notifyAll(Game)} + the {@code ClientHandler.notifyModel} - * call that stores the model for disconnect-turn checking. + * Notifies all connected RMI clients of a new game model. + * + *

The updated mini model is sent to each registered client callback. + * If a communication error occurs for a client, the exception is logged + * without interrupting the notification of the remaining clients. + * + * @param model the updated mini model to send to the connected clients. */ public void notifyAll(MiniModel model) { - // Keep every watchdog's game reference up to date - synchronized (controller){ - watchdogs.values().forEach(wd -> wd.setGame(controller.getModel())); - } for (IClientCallback cb : clients.values()) { try{ cb.onGameInit(model); @@ -188,17 +213,6 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { } } - - - /** - * Push an action in actionQueue. - * @param action The desired actio - * @return true if the action was successfully added, false otherwise - */ - public boolean doEvent(NetworkEvent action) { - return actionQueue.offer(action); - } - /** * Requests to draw a tribe card from the upper list. * Creates a NetworkEvent and sends it through the network client. @@ -269,10 +283,17 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { } - // Metodi per avviare server RMI /** - * Starts the RMI server. - * @return true if the server starts successfully, false otherwise + * Starts the RMI server and binds it to the configured registry. + * + *

The method configures the server hostname, creates the RMI registry + * on the specified port, and registers this server instance under the + * {@code RMIGameServer} name. + * + * @param serverCrashed {@code true} if the server is being restarted after a crash, + * {@code false} otherwise. + * @return {@code true} if the server starts successfully, + * {@code false} otherwise. */ public boolean start(boolean serverCrashed) { this.serverCrashed = serverCrashed; @@ -288,12 +309,21 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { } } + /** + * Stops the RMI server and removes its binding from the registry. + * + *

The remote server object is unexported, the registry entry associated + * with {@code RMIGameServer} is removed, and the server shutdown is logged. + * + * @return {@code true} if the server is stopped successfully, + * {@code false} otherwise. + */ public boolean stop() { try { registry.unbind("RMIGameServer"); UnicastRemoteObject.unexportObject(this, true); watchdogs.values().forEach(wd -> { /* watchdogs shut themselves down */ }); - System.out.println("RMI Server fermato"); + System.out.println("RMI Server stopped"); return true; } catch (RemoteException | NotBoundException e) { e.printStackTrace(); @@ -303,17 +333,13 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { /** - * Creates and starts a {@link RMIHeartbeat} for {@code username}. - * Also seeds the watchdog with the current model if one already exists - * (reconnection case). + * Creates and starts an {@link RMIHeartbeat} for the specified player. + * + * @param username the username of the player monitored by the heartbeat watchdog. */ private void startWatchdog(String username) { RMIHeartbeat wd = new RMIHeartbeat( username, playerList, clients, actionQueue); - synchronized (controller) - { - if (controller.getModel() != null) wd.setGame(controller.getModel()); - } watchdogs.put(username, wd); wd.start(); } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java index efd91db..28598d4 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java @@ -46,10 +46,12 @@ public class TCPClient implements IClient { /** - * Class constructor that initializes the attributes. - * @param controller The game controller - * @param hostname The IP address of the server - * @param port The TCP port of the server + * Constructs a TCP client and initializes its connection parameters. + * + * @param controller the client controller. + * @param hostname the IP address or hostname of the server. + * @param mainPort the main TCP port of the server. + * @param heartbeatPort the TCP port used for heartbeat communication. */ public TCPClient(ClientController controller, String hostname, int mainPort,int heartbeatPort ) { this.controller = controller; diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/ClientHandler.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/ClientHandler.java index 15773f7..8e36e01 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/ClientHandler.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/ClientHandler.java @@ -58,12 +58,13 @@ public class ClientHandler implements Runnable { /** * Class constructor that initializes the attributes. * - * @param username the username associated with the client. - * @param clientSocket the socket representing the client's TCP connection. - * @param out the output stream used to send data to the client. - * @param in the input stream used to receive data from the client. + * @param username the username associated with the client. + * @param clientSocket the socket representing the client's TCP connection. + * @param out the output stream used to send data to the client. + * @param in the input stream used to receive data from the client. * @param clientHandlers the shared list of all active client handlers. - * @param actionQueue the queue containing incoming events. + * @param playersMap the shared map containing the connected players. + * @param actionQueue the queue containing incoming events. */ public ClientHandler(String username, Socket clientSocket, ObjectOutputStream out, ObjectInputStream in, List clientHandlers, LimitedMap playersMap, BlockingQueue actionQueue) { this.username=username; @@ -130,6 +131,13 @@ public class ClientHandler implements Runnable { } } + /** + * Disconnects the client from the server. + * + *

The client handler is stopped and removed from the list of active handlers. + * The player is marked as disconnected, a {@link DisconnectedPlayer} event is + * added to the action queue, and the associated socket is closed. + */ public void disconnect() { running = false; clientHandlers.remove(this); diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/HeartbeatHandler.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/HeartbeatHandler.java index a0dde68..fdf9f8e 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/HeartbeatHandler.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/HeartbeatHandler.java @@ -4,12 +4,26 @@ import java.io.*; import java.net.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; +/** + * Handles the heartbeat communication associated with a TCP client. + * + *

This component listens for heartbeat {@code PING} messages from the client, + * replies with {@code PONG} messages, and periodically checks whether the client + * has remained silent for too long. If a timeout or communication error occurs, + * both the heartbeat connection and the main client connection are disconnected. + */ public class HeartbeatHandler implements Runnable { + /** + * Maximum allowed time without receiving heartbeat messages before disconnecting the client. + */ private static final long SILENCE_THRESHOLD_MS = 5_000; + + /** + * Expected interval between heartbeat messages. + */ private static final long KEEPALIVE_INTERVAL_MS = 3_000; private final String username; @@ -17,18 +31,46 @@ public class HeartbeatHandler implements Runnable { private final InputStream in; private final OutputStream out; + /** + * Byte value representing a heartbeat ping message. + */ private static final int PING = 1; + + /** + * Byte value representing a heartbeat pong response. + */ private static final int PONG = 2; - // riferimento al ClientHandler principale per disconnetterlo insieme + /** + * Main client handler associated with this heartbeat connection. + */ private final ClientHandler mainHandler; + /** + * Timestamp of the last received heartbeat message. + */ private volatile long lastReceivedTime = System.currentTimeMillis(); + + /** + * Indicates whether the heartbeat handler is still active. + */ private volatile boolean running = true; + + /** + * Executor used to periodically check heartbeat timeouts. + */ private final ScheduledExecutorService watchdog = Executors.newSingleThreadScheduledExecutor(); + /** + * Constructs a heartbeat handler for the specified client. + * + * @param username the username of the connected client. + * @param socket the socket dedicated to heartbeat communication. + * @param mainHandler the main client handler associated with the same player. + * @throws IOException if the input or output stream cannot be obtained from the socket. + */ public HeartbeatHandler(String username, Socket socket, ClientHandler mainHandler) throws IOException { this.username = username; @@ -38,6 +80,14 @@ public class HeartbeatHandler implements Runnable { this.out = socket.getOutputStream(); } + /** + * Starts the heartbeat listening loop. + * + *

The method activates the watchdog task, then waits for incoming heartbeat + * messages. When a {@code PING} is received, the last-received timestamp is + * updated and a {@code PONG} response is sent back to the client. + * If the stream is closed or an I/O error occurs, the client is disconnected. + */ @Override public void run() { startWatchdog(); @@ -56,6 +106,12 @@ public class HeartbeatHandler implements Runnable { } } + /** + * Starts the periodic watchdog task that detects heartbeat timeouts. + * + *

If no heartbeat message is received within the configured silence threshold, + * the associated client is disconnected. + */ private void startWatchdog() { watchdog.scheduleAtFixedRate(() -> { if (System.currentTimeMillis() - lastReceivedTime > SILENCE_THRESHOLD_MS) { @@ -65,7 +121,12 @@ public class HeartbeatHandler implements Runnable { }, 1, 1, TimeUnit.SECONDS); } - + /** + * Disconnects the heartbeat channel and the associated main client connection. + * + *

The handler is stopped, the watchdog task is terminated, the main + * {@link ClientHandler} is disconnected, and the heartbeat socket is closed. + */ private void disconnect() { running = false; watchdog.shutdownNow(); diff --git a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java index 64fd1e6..25b1f5e 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java +++ b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java @@ -192,15 +192,26 @@ public class ServerLauncher { /** - * The first method executed when the server program is launched. - * It creates all the objects needed: playerList, actionQueue, gameController, serverRMI, serverTCP, launcher. - * Then sets the playerList's action to execute launcher.run() and starts the TCP/RMI servers. - * Note: the model is initialized and set in the controller in TCP/RMI servers when the first user decides the number of players. + * Entry point of the server application. * - * @throws InterruptedException if this exception is issued by run method - * @throws RemoteException if this exception is issued by run method + *

The method initializes the shared player list, the network event queue, + * the game controller, the RMI server, the TCP server, and the server launcher. + * It also selects the network interface to expose, configures the server crash + * recovery state, and defines the action to execute once the required number + * of players has joined the game. + * + *

When the player list reaches its limit, the current game model is converted + * into a {@link MiniModel}, sent to all connected clients through both RMI and TCP, + * and rendered on the server-side TUI. Finally, the event-processing launcher + * and both network servers are started. + * + *

The game model itself is initialized by the TCP or RMI server when the first + * player joins and selects the total number of players. + * + * @param args the command-line arguments passed to the server application. + * @throws RemoteException if the RMI server cannot be created. */ - public static void main(String[] args) throws InterruptedException, RemoteException { + public static void main(String[] args) throws RemoteException { playerList = new LimitedMap(5, ()->{}); BlockingQueue actionQueue = new LinkedBlockingQueue<>(); GameController gameController = new GameController(); @@ -261,10 +272,13 @@ public class ServerLauncher { /** - * Creates and executes the game. - * Game creation: TCP/RMI servers send the game model to all players. - * Game execution: repeatedly calls doFirstEvent() to process the events in the actionQueue. - * @throws InterruptedException if the TCP server thread is interrupted + * Executes the main game loop. + * + *

The method repeatedly processes the first event in the action queue + * and, when a view is available, updates the rendered game state. + * + *

If the thread is interrupted while waiting for an event, + * the interruption status is restored and the loop terminates. */ public void run() { while (true) { @@ -282,6 +296,18 @@ public class ServerLauncher { } } + /** + * Lets the user choose the network interface to be used by the server. + * + *

The method scans all active, non-loopback, and non-virtual network + * interfaces, collecting their IPv4 addresses. If only one valid address is + * found, it is selected automatically. Otherwise, the available addresses are + * printed and the user is asked to choose one by index. + * + * @param scanner the scanner used to read the user's selection. + * @return the IPv4 address of the selected network interface. + * @throws Exception if no valid network interface is available. + */ public static String chooseNetworkInterface(Scanner scanner) throws Exception { List ips = new ArrayList<>(); @@ -315,6 +341,16 @@ public class ServerLauncher { return ips.get(choice); } + /** + * Saves the current game model to a local file. + * + *

The save file is stored in the {@code GameSaves/save.dat} path relative + * to the server executable location. If the directory does not exist, it is + * created before writing the serialized game model. + * + * @return {@code true} if the game is saved successfully, + * {@code false} otherwise. + */ private boolean gameSave(){ try{ Path jarPath = Paths.get(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); @@ -340,6 +376,16 @@ public class ServerLauncher { } } + /** + * Loads a previously saved game model from the local save file. + * + *

The method attempts to deserialize the game stored in + * {@code GameSaves/save.dat}. If no save file exists or an I/O error occurs, + * {@code null} is returned. + * + * @return the loaded {@link Game} instance, or {@code null} if no valid save + * can be loaded. + */ private Game loadSave(){ try { Path jarPath = Paths.get(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); @@ -363,6 +409,12 @@ public class ServerLauncher { } } + /** + * Deletes the current local game save file. + * + * @return {@code true} if the save file is deleted successfully, + * {@code false} otherwise. + */ private boolean deleteSave(){ try{ Path jarPath = Paths.get(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/TotemFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/TotemFXMLController.java index 1241146..c9bd7b9 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/TotemFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/TotemFXMLController.java @@ -16,7 +16,6 @@ import javafx.stage.Screen; import javafx.util.Duration; import java.util.Locale; -import java.util.Objects; public class TotemFXMLController { diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java index 6914e40..504ee6e 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java @@ -185,6 +185,13 @@ public class TUI implements IView { System.out.println(AsciiTable.sideBySide(lines, lines2, 3)); } + /** + * Renders the available totems in the terminal interface. + * + *

The method clears the terminal, builds a table containing the currently + * available totems together with their selection positions, and displays the + * instructions required to choose one. + */ public void renderTotems() { clearTerminal(); var table = new AsciiTable(BorderStyle.ROUNDED, model.availableTotems.size());