Add: complete JavaDoc for networking, heartbeat, totem flow and game events
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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<Slot, Player> 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<Slot, Player> 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<Slot, Player> 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);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,15 @@ import java.util.Map;
|
||||
public class ApplyNextRound extends NetworkEvent implements Serializable{
|
||||
|
||||
List<Player> 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<Slot, Player> slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, List<Player> players){
|
||||
super("SERVER",EventType.NEXT_ROUND,false);
|
||||
this.slotPlayerMap = slotPlayerMap;
|
||||
|
||||
@@ -21,7 +21,15 @@ import java.util.Map;
|
||||
public class EndedGame extends NetworkEvent implements Serializable{
|
||||
|
||||
ArrayList<Player> 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<Slot, Player> slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, ArrayList<Player> players){
|
||||
super("SERVER",EventType.ENDED_GAME,false);
|
||||
this.slotPlayerMap = slotPlayerMap;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 List<Totems>availableTotems;
|
||||
|
||||
/**
|
||||
* List of totems still available after the choice has been processed.
|
||||
*/
|
||||
private List<Totems> availableTotems;
|
||||
|
||||
/**
|
||||
* Sets the list of currently available totems.
|
||||
*
|
||||
* @param availableTotems the totems still available for selection.
|
||||
*/
|
||||
public void setAvailableTotems(List<Totems> 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.
|
||||
*
|
||||
* <p>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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>If no ping is received within {@value SILENCE_THRESHOLD_MS} ms the player is
|
||||
* <p>If no ping is received within {@value SILENCE_THRESHOLD_MS} ms, the player is
|
||||
* considered disconnected and {@link #disconnect()} is invoked, which:
|
||||
* <ul>
|
||||
* <li>stops the watchdog;</li>
|
||||
* <li>marks the player as offline in {@code playerList};</li>
|
||||
* <li>removes the callback from {@code clients};</li>
|
||||
* <li>optionally pushes a {@link DisconnectedPlayer} event if it was that
|
||||
* player's turn.</li>
|
||||
* <li>adds a {@link DisconnectedPlayer} event to the action queue.</li>
|
||||
* </ul>
|
||||
*/
|
||||
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<String, Boolean> 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.
|
||||
*
|
||||
* <p>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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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<String, Boolean> 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<NetworkEvent> actionQueue,
|
||||
LimitedMap<String, Boolean> 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.
|
||||
*
|
||||
* <p>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<String, IClientCallback> 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ClientHandler> clientHandlers, LimitedMap<String,Boolean> playersMap, BlockingQueue<NetworkEvent> actionQueue) {
|
||||
this.username=username;
|
||||
@@ -130,6 +131,13 @@ public class ClientHandler implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the client from the server.
|
||||
*
|
||||
* <p>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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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();
|
||||
|
||||
Reference in New Issue
Block a user