Fix: full network stack refactor
This commit is contained in:
@@ -10,7 +10,7 @@ public enum ErrorType {
|
|||||||
GENERIC_ERROR("Generic error"),
|
GENERIC_ERROR("Generic error"),
|
||||||
GAME_ALREADY_STARTED("Game already started"),
|
GAME_ALREADY_STARTED("Game already started"),
|
||||||
WRONG_ACTION("Wrong action");
|
WRONG_ACTION("Wrong action");
|
||||||
private String description;
|
private final String description;
|
||||||
ErrorType(String description) {
|
ErrorType(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ public class GameEventProcessor {
|
|||||||
event.setIsError(!event.apply(gameController));
|
event.setIsError(!event.apply(gameController));
|
||||||
Game game = gameController.getModel();
|
Game game = gameController.getModel();
|
||||||
|
|
||||||
if (event.getIsError()) {
|
if (event.isError()) {
|
||||||
broadcaster.notifyAll(event);
|
broadcaster.notifyAll(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,10 +191,82 @@ public class MiniModel implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param standingPlayers the final ordered list of players.
|
* @param standingPlayers the final ordered list of players.
|
||||||
*/
|
*/
|
||||||
public void setStandingPlayers(ArrayList<Player> standingPlayers) {
|
public void setStandingPlayers(List<Player> standingPlayers) {
|
||||||
this.standingPlayers = standingPlayers;
|
this.standingPlayers = standingPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the upper row of tribe cards on the board.
|
||||||
|
*
|
||||||
|
* @param cards the new upper tribe card list.
|
||||||
|
*/
|
||||||
|
public void setUpperListTribeCards(ArrayList<TribeCard> cards) {
|
||||||
|
this.upperListTribeCards = cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the lower row of tribe cards on the board.
|
||||||
|
*
|
||||||
|
* @param cards the new lower tribe card list.
|
||||||
|
*/
|
||||||
|
public void setLowerListTribeCards(ArrayList<TribeCard> cards) {
|
||||||
|
this.lowerListTribeCards = cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the upper row of building cards on the board.
|
||||||
|
*
|
||||||
|
* @param cards the new upper building card list.
|
||||||
|
*/
|
||||||
|
public void setUpperListBuildingCards(ArrayList<BuildingCard> cards) {
|
||||||
|
this.upperListBuildingCards = cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the lower row of building cards on the board.
|
||||||
|
*
|
||||||
|
* @param cards the new lower building card list.
|
||||||
|
*/
|
||||||
|
public void setLowerListBuildingCards(ArrayList<BuildingCard> cards) {
|
||||||
|
this.lowerListBuildingCards = cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the card at the given position from the upper tribe card list.
|
||||||
|
*
|
||||||
|
* @param pos the zero-based index of the card to remove.
|
||||||
|
*/
|
||||||
|
public void removeUpperTribeCard(int pos) {
|
||||||
|
if (upperListTribeCards != null) upperListTribeCards.remove(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the card at the given position from the lower tribe card list.
|
||||||
|
*
|
||||||
|
* @param pos the zero-based index of the card to remove.
|
||||||
|
*/
|
||||||
|
public void removeLowerTribeCard(int pos) {
|
||||||
|
if (lowerListTribeCards != null) lowerListTribeCards.remove(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the card at the given position from the upper building card list.
|
||||||
|
*
|
||||||
|
* @param pos the zero-based index of the card to remove.
|
||||||
|
*/
|
||||||
|
public void removeUpperBuildingCard(int pos) {
|
||||||
|
if (upperListBuildingCards != null) upperListBuildingCards.remove(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the card at the given position from the lower building card list.
|
||||||
|
*
|
||||||
|
* @param pos the zero-based index of the card to remove.
|
||||||
|
*/
|
||||||
|
public void removeLowerBuildingCard(int pos) {
|
||||||
|
if (lowerListBuildingCards != null) lowerListBuildingCards.remove(pos);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the position of the player with the specified username
|
* Returns the position of the player with the specified username
|
||||||
* within the player collection.
|
* within the player collection.
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public enum EventType {
|
|||||||
*/
|
*/
|
||||||
ENDED_GAME("Ended Game");
|
ENDED_GAME("Ended Game");
|
||||||
|
|
||||||
private String description;
|
private final String description;
|
||||||
private EventType(String description) {
|
private EventType(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ public interface IClient {
|
|||||||
* and preferred connection type.
|
* and preferred connection type.
|
||||||
*
|
*
|
||||||
* @param username the username chosen by the player.
|
* @param username the username chosen by the player.
|
||||||
* @param preferredInt the preferred connection type selected by the client.
|
* @param proposedNPlayers the desired number of players proposed by this client.
|
||||||
* @return {@code true} if the connection is established successfully,
|
* @return {@code true} if the connection is established successfully,
|
||||||
* {@code false} otherwise.
|
* {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
ErrorType connect(String username, int preferredInt);
|
ErrorType connect(String username, int proposedNPlayers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests to draw a tribe card from the upper tribe card list.
|
* Requests to draw a tribe card from the upper tribe card list.
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ public final class NetworkConfig {
|
|||||||
public static final long SILENCE_THRESHOLD_MS = 5_000;
|
public static final long SILENCE_THRESHOLD_MS = 5_000;
|
||||||
/** Milliseconds between keep-alive pings sent by the client. */
|
/** Milliseconds between keep-alive pings sent by the client. */
|
||||||
public static final long KEEPALIVE_INTERVAL_MS = 3_000;
|
public static final long KEEPALIVE_INTERVAL_MS = 3_000;
|
||||||
|
/** Minimum number of players required to start a game. */
|
||||||
|
public static final int MIN_PLAYERS = 2;
|
||||||
|
/** Maximum number of players allowed in a game. */
|
||||||
|
public static final int MAX_PLAYERS = 5;
|
||||||
|
|
||||||
private NetworkConfig() {}
|
private NetworkConfig() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,15 +80,6 @@ public abstract class NetworkEvent implements Serializable {
|
|||||||
*/
|
*/
|
||||||
protected ArrayList<String> disconnectedPlayers;
|
protected ArrayList<String> disconnectedPlayers;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the list of currently disconnected player usernames.
|
|
||||||
*
|
|
||||||
* @param players the list of disconnected player usernames to attach to this event.
|
|
||||||
*/
|
|
||||||
public void setDisconnected(ArrayList<String> players) {
|
|
||||||
this.disconnectedPlayers = players;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates this event with the current game state so clients can
|
* Populates this event with the current game state so clients can
|
||||||
* update their local model after receiving it.
|
* update their local model after receiving it.
|
||||||
@@ -140,7 +131,7 @@ public abstract class NetworkEvent implements Serializable {
|
|||||||
* @return {@code true} if the event could not be applied successfully,
|
* @return {@code true} if the event could not be applied successfully,
|
||||||
* {@code false} otherwise.
|
* {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean getIsError() {
|
public boolean isError() {
|
||||||
return isError;
|
return isError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +145,15 @@ public abstract class NetworkEvent implements Serializable {
|
|||||||
this.isError = isError;
|
this.isError = isError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the error type for this event.
|
||||||
|
*
|
||||||
|
* @param errorType the error type to set.
|
||||||
|
*/
|
||||||
|
public void setErrorType(ErrorType errorType) {
|
||||||
|
this.errorType = errorType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a network event.
|
* Constructs a network event.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,20 +7,15 @@ import it.polimi.ingsw.gc14.Network.EventType;
|
|||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkEvent to add a player.
|
* Network event used to register a new player in the lobby.
|
||||||
|
*
|
||||||
|
* <p>The first player to join also proposes the desired number of players
|
||||||
|
* for the match. Subsequent joiners ignore {@code proposedNPlayer} if the
|
||||||
|
* game has already been created.
|
||||||
*/
|
*/
|
||||||
public class AddPlayer extends NetworkEvent {
|
public class AddPlayer extends NetworkEvent {
|
||||||
/** Number of proposed players to add to the match */
|
/** Number of players proposed by this player; used only when creating a new game. */
|
||||||
private int proposedNPlayer;
|
private int proposedNPlayer;
|
||||||
/**
|
|
||||||
* Overrides the default error type for this event.
|
|
||||||
*
|
|
||||||
* @param errorType the error type to set.
|
|
||||||
*/
|
|
||||||
public void setErrorType(ErrorType errorType)
|
|
||||||
{
|
|
||||||
this.errorType = errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the number of proposed players to add to the match
|
* @return the number of proposed players to add to the match
|
||||||
|
|||||||
@@ -17,15 +17,19 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkEvent to draw a tribe card from the lower card list.
|
* Network event that transitions all clients to the next round.
|
||||||
|
*
|
||||||
|
* <p>Carries refreshed card lists for all four board rows in addition
|
||||||
|
* to the standard game state (slot map, turn order, current state,
|
||||||
|
* player list). Only applied client-side; {@link #apply(GameController)}
|
||||||
|
* always returns {@code false}.
|
||||||
*/
|
*/
|
||||||
public class ApplyNextRound extends NetworkEvent {
|
public class ApplyNextRound extends NetworkEvent {
|
||||||
|
|
||||||
List<Player> players;
|
private ArrayList<TribeCard> upperListTribeCards;
|
||||||
ArrayList<TribeCard> upperListTribeCards;
|
private ArrayList<TribeCard> lowerListTribeCards;
|
||||||
ArrayList<TribeCard> lowerListTribeCards;
|
private ArrayList<BuildingCard> upperListBuildingCards;
|
||||||
ArrayList<BuildingCard> upperListBuildingCards;
|
private ArrayList<BuildingCard> lowerListBuildingCards;
|
||||||
ArrayList<BuildingCard> lowerListBuildingCards;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,27 +39,38 @@ public class ApplyNextRound extends NetworkEvent{
|
|||||||
* @param orderLogicCard the order logic card that determines the player order.
|
* @param orderLogicCard the order logic card that determines the player order.
|
||||||
* @param currentState the current state of the game.
|
* @param currentState the current state of the game.
|
||||||
* @param players the list of players in the game.
|
* @param players the list of players in the game.
|
||||||
|
* @param upperListTribeCards the upper row of tribe cards for the new round.
|
||||||
|
* @param lowerListTribeCards the lower row of tribe cards for the new round.
|
||||||
|
* @param upperListBuildingCards the upper row of building cards for the new round.
|
||||||
|
* @param lowerListBuildingCards the lower row of building cards for the new round.
|
||||||
*/
|
*/
|
||||||
public ApplyNextRound(Map<Slot, Player> slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, List<Player> players, ArrayList<TribeCard> upperListTribeCards, ArrayList<TribeCard>lowerListTribeCards, ArrayList<BuildingCard> upperListBuildingCards, ArrayList<BuildingCard>lowerListBuildingCards) {
|
public ApplyNextRound(Map<Slot, Player> slotPlayerMap,
|
||||||
|
OrderLogicCard orderLogicCard,
|
||||||
|
CurrentState currentState,
|
||||||
|
List<Player> players,
|
||||||
|
ArrayList<TribeCard> upperListTribeCards,
|
||||||
|
ArrayList<TribeCard> lowerListTribeCards,
|
||||||
|
ArrayList<BuildingCard> upperListBuildingCards,
|
||||||
|
ArrayList<BuildingCard> lowerListBuildingCards) {
|
||||||
super("SERVER", EventType.NEXT_ROUND, false, ErrorType.WRONG_ACTION);
|
super("SERVER", EventType.NEXT_ROUND, false, ErrorType.WRONG_ACTION);
|
||||||
|
setData(slotPlayerMap, orderLogicCard, currentState, players);
|
||||||
this.upperListBuildingCards = upperListBuildingCards;
|
this.upperListBuildingCards = upperListBuildingCards;
|
||||||
this.lowerListBuildingCards = lowerListBuildingCards;
|
this.lowerListBuildingCards = lowerListBuildingCards;
|
||||||
this.upperListTribeCards = upperListTribeCards;
|
this.upperListTribeCards = upperListTribeCards;
|
||||||
this.lowerListTribeCards = lowerListTribeCards;
|
this.lowerListTribeCards = lowerListTribeCards;
|
||||||
this.slotPlayerMap = slotPlayerMap;
|
|
||||||
this.orderLogicCard = orderLogicCard;
|
|
||||||
this.currentState = currentState;
|
|
||||||
this.players = players;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param gameController the Game Controller on which to apply the event
|
* Not applicable server-side.
|
||||||
* @return true if the player could draw the card, false otherwise
|
*
|
||||||
|
* @param gameController the game controller (unused).
|
||||||
|
* @return {@code false} always.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(GameController gameController) {
|
public boolean apply(GameController gameController) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this event to the client-side mini model, updating all board lists,
|
* Applies this event to the client-side mini model, updating all board lists,
|
||||||
* slot map, turn order, and game state for the new round.
|
* slot map, turn order, and game state for the new round.
|
||||||
@@ -63,20 +78,19 @@ public class ApplyNextRound extends NetworkEvent{
|
|||||||
* @param miniModel the client-side model to update.
|
* @param miniModel the client-side model to update.
|
||||||
* @return {@code true} always (this event cannot produce an error).
|
* @return {@code true} always (this event cannot produce an error).
|
||||||
*/
|
*/
|
||||||
public boolean apply(MiniModel miniModel)
|
@Override
|
||||||
{
|
public boolean apply(MiniModel miniModel) {
|
||||||
synchronized (miniModel) {
|
synchronized (miniModel) {
|
||||||
miniModel.setSlotPlayerMap(slotPlayerMap);
|
miniModel.setSlotPlayerMap(slotPlayerMap);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
miniModel.setPlayers(players);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.upperListTribeCards = upperListTribeCards;
|
miniModel.setUpperListTribeCards(upperListTribeCards);
|
||||||
miniModel.lowerListTribeCards = lowerListTribeCards;
|
miniModel.setLowerListTribeCards(lowerListTribeCards);
|
||||||
miniModel.upperListBuildingCards = upperListBuildingCards;
|
miniModel.setUpperListBuildingCards(upperListBuildingCards);
|
||||||
miniModel.lowerListBuildingCards = lowerListBuildingCards;
|
miniModel.setLowerListBuildingCards(lowerListBuildingCards);
|
||||||
miniModel.setLastEvent(this);
|
miniModel.setLastEvent(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,16 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
|||||||
import it.polimi.ingsw.gc14.Model.Game;
|
import it.polimi.ingsw.gc14.Model.Game;
|
||||||
import it.polimi.ingsw.gc14.Model.Totems;
|
import it.polimi.ingsw.gc14.Model.Totems;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkEvent to avoid drawing a card from the lower card list
|
* Network event used to notify all clients that a player has disconnected.
|
||||||
|
*
|
||||||
|
* <p>Also carries the updated list of available totems, since a disconnection
|
||||||
|
* during totem selection may free a totem for other players.
|
||||||
*/
|
*/
|
||||||
public class DisconnectedPlayer extends NetworkEvent implements Serializable{
|
public class DisconnectedPlayer extends NetworkEvent {
|
||||||
|
|
||||||
private List<Totems> availableTotems;
|
private List<Totems> availableTotems;
|
||||||
|
|
||||||
@@ -29,18 +31,19 @@ public class DisconnectedPlayer extends NetworkEvent implements Serializable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Constructs a disconnection event for the specified player.
|
||||||
* Initializes all the attributes.
|
*
|
||||||
* @param username the name of the player requesting the event
|
* @param username the username of the player who disconnected.
|
||||||
*/
|
*/
|
||||||
public DisconnectedPlayer(String username) {
|
public DisconnectedPlayer(String username) {
|
||||||
super(username, EventType.DISCONNECTED_PLAYER, false, ErrorType.GENERIC_ERROR);
|
super(username, EventType.DISCONNECTED_PLAYER, false, ErrorType.GENERIC_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param gameController the Game Controller on which to apply the event
|
* Applies this disconnection event to the server-side game controller.
|
||||||
* @return true if the player could skipTheTurn, false otherwise
|
*
|
||||||
|
* @param gameController the game controller on which to apply the event.
|
||||||
|
* @return {@code true} if the disconnection is handled successfully.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(GameController gameController){
|
public boolean apply(GameController gameController){
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class DrawLowerBuildingCard extends NetworkEvent{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
* Initialized all the attributes.
|
* Initializes all the attributes.
|
||||||
* @param username the name of the player requesting the event
|
* @param username the name of the player requesting the event
|
||||||
* @param pos the index of the card to draw
|
* @param pos the index of the card to draw
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +48,7 @@ public class DrawLowerBuildingCard extends NetworkEvent{
|
|||||||
if (isError)
|
if (isError)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
miniModel.lowerListBuildingCards.remove(pos);
|
miniModel.removeLowerBuildingCard(pos);
|
||||||
miniModel.setPlayers(playerList);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class DrawLowerTribeCard extends NetworkEvent{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
* Initialized all the attributes.
|
* Initializes all the attributes.
|
||||||
* @param username the name of the player requesting the event
|
* @param username the name of the player requesting the event
|
||||||
* @param pos the index of the card to draw
|
* @param pos the index of the card to draw
|
||||||
*/
|
*/
|
||||||
@@ -47,7 +47,7 @@ public class DrawLowerTribeCard extends NetworkEvent{
|
|||||||
if (isError)
|
if (isError)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
miniModel.lowerListTribeCards.remove(pos);
|
miniModel.removeLowerTribeCard(pos);
|
||||||
miniModel.setPlayers(playerList);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class DrawUpperBuildingCard extends NetworkEvent{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
* Initialized all the attributes.
|
* Initializes all the attributes.
|
||||||
* @param username the name of the player requesting the event
|
* @param username the name of the player requesting the event
|
||||||
* @param pos the index of the card to draw
|
* @param pos the index of the card to draw
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +48,7 @@ public class DrawUpperBuildingCard extends NetworkEvent{
|
|||||||
if (isError)
|
if (isError)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
miniModel.upperListBuildingCards.remove(pos);
|
miniModel.removeUpperBuildingCard(pos);
|
||||||
miniModel.setPlayers(playerList);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class DrawUpperTribeCard extends NetworkEvent{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
* Initialized all the attributes.
|
* Initializes all the attributes.
|
||||||
* @param username the name of the player requesting the event
|
* @param username the name of the player requesting the event
|
||||||
* @param pos the index of the card to draw
|
* @param pos the index of the card to draw
|
||||||
*/
|
*/
|
||||||
@@ -46,7 +46,7 @@ public class DrawUpperTribeCard extends NetworkEvent{
|
|||||||
synchronized (miniModel) {
|
synchronized (miniModel) {
|
||||||
if (isError)
|
if (isError)
|
||||||
return false;
|
return false;
|
||||||
miniModel.upperListTribeCards.remove(pos);
|
miniModel.removeUpperTribeCard(pos);
|
||||||
miniModel.setPlayers(playerList);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
|
|||||||
@@ -11,58 +11,59 @@ import it.polimi.ingsw.gc14.Network.EventType;
|
|||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkEvent to draw a tribe card from the lower card list.
|
* Network event that signals the end of the game and delivers the final standings.
|
||||||
|
*
|
||||||
|
* <p>Only applied client-side; {@link #apply(GameController)} always returns {@code false}.
|
||||||
*/
|
*/
|
||||||
public class EndedGame extends NetworkEvent {
|
public class EndedGame extends NetworkEvent {
|
||||||
|
|
||||||
ArrayList<Player> players;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an event containing the final game state.
|
* Constructs an event containing the final game state.
|
||||||
*
|
*
|
||||||
* @param slotPlayerMap the map associating each slot with the player occupying it.
|
* @param slotPlayerMap the map associating each slot with the player occupying it.
|
||||||
* @param orderLogicCard the order logic card that determines the player order.
|
* @param orderLogicCard the order logic card that determines the player order.
|
||||||
* @param currentState the current state of the game.
|
* @param currentState the current state of the game.
|
||||||
* @param players the list of players at the end of the game.
|
* @param players the final list of players, used as the standings.
|
||||||
*/
|
*/
|
||||||
public EndedGame(Map<Slot, Player> slotPlayerMap, OrderLogicCard orderLogicCard, CurrentState currentState, ArrayList<Player> players){
|
public EndedGame(Map<Slot, Player> slotPlayerMap,
|
||||||
|
OrderLogicCard orderLogicCard,
|
||||||
|
CurrentState currentState,
|
||||||
|
ArrayList<Player> players) {
|
||||||
super("SERVER", EventType.ENDED_GAME, false, ErrorType.GENERIC_ERROR);
|
super("SERVER", EventType.ENDED_GAME, false, ErrorType.GENERIC_ERROR);
|
||||||
this.slotPlayerMap = slotPlayerMap;
|
setData(slotPlayerMap, orderLogicCard, currentState, players);
|
||||||
this.orderLogicCard = orderLogicCard;
|
|
||||||
this.currentState = currentState;
|
|
||||||
this.players = players;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param gameController the Game Controller on which to apply the event
|
* Not applicable server-side.
|
||||||
* @return true if the player could draw the card, false otherwise
|
*
|
||||||
|
* @param gameController the game controller (unused).
|
||||||
|
* @return {@code false} always.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(GameController gameController) {
|
public boolean apply(GameController gameController) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this event to the client-side mini model, updating the final
|
* Applies this event to the client-side mini model, updating the final
|
||||||
* game state and setting the standing players list for the leaderboard.
|
* game state and setting the standings list for the leaderboard.
|
||||||
*
|
*
|
||||||
* @param miniModel the client-side model to update.
|
* @param miniModel the client-side model to update.
|
||||||
* @return {@code true} always (this event cannot produce an error).
|
* @return {@code true} always (this event cannot produce an error).
|
||||||
*/
|
*/
|
||||||
public boolean apply(MiniModel miniModel)
|
@Override
|
||||||
{
|
public boolean apply(MiniModel miniModel) {
|
||||||
synchronized (miniModel) {
|
synchronized (miniModel) {
|
||||||
miniModel.setSlotPlayerMap(slotPlayerMap);
|
miniModel.setSlotPlayerMap(slotPlayerMap);
|
||||||
miniModel.setOrderLogicCard(orderLogicCard);
|
miniModel.setOrderLogicCard(orderLogicCard);
|
||||||
miniModel.setCurrentState(currentState);
|
miniModel.setCurrentState(currentState);
|
||||||
miniModel.setPlayers(players);
|
miniModel.setPlayers(playerList);
|
||||||
miniModel.setStandingPlayers(players);
|
miniModel.setStandingPlayers(playerList);
|
||||||
miniModel.setLastEvent(this);
|
miniModel.setLastEvent(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import it.polimi.ingsw.gc14.Model.MiniModel;
|
|||||||
import it.polimi.ingsw.gc14.Network.EventType;
|
import it.polimi.ingsw.gc14.Network.EventType;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Network event used to notify that a player has reconnected to the game.
|
* Network event used to notify that a player has reconnected to the game.
|
||||||
*/
|
*/
|
||||||
public class ReconnectPlayer extends NetworkEvent implements Serializable {
|
public class ReconnectPlayer extends NetworkEvent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enrichWithGameState(Game game, ArrayList<String> disconnectedUsernames) {
|
public void enrichWithGameState(Game game, ArrayList<String> disconnectedUsernames) {
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import it.polimi.ingsw.gc14.Model.MiniModel;
|
|||||||
import it.polimi.ingsw.gc14.Network.EventType;
|
import it.polimi.ingsw.gc14.Network.EventType;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkEvent to avoid drawing a card from the lower card list
|
* Network event used to skip the current player's optional card action.
|
||||||
*/
|
*/
|
||||||
public class SkipTurn extends NetworkEvent implements Serializable{
|
public class SkipTurn extends NetworkEvent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
|||||||
*/
|
*/
|
||||||
public class SlotChoice extends NetworkEvent {
|
public class SlotChoice extends NetworkEvent {
|
||||||
|
|
||||||
/** Index of the card to draw */
|
/** Index of the selected slot. */
|
||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor.
|
* Class constructor.
|
||||||
* Initializes all the attributes.
|
* Initializes all the attributes.
|
||||||
* @param username the name of the player requesting the event
|
* @param username the name of the player requesting the event
|
||||||
* @param pos the index of the card to draw
|
* @param pos the index of the selected slot
|
||||||
*/
|
*/
|
||||||
public SlotChoice(String username, int pos) {
|
public SlotChoice(String username, int pos) {
|
||||||
super(username, EventType.SLOT_CHOICE, false, ErrorType.WRONG_ACTION);
|
super(username, EventType.SLOT_CHOICE, false, ErrorType.WRONG_ACTION);
|
||||||
@@ -27,8 +27,8 @@ public class SlotChoice extends NetworkEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param gameController the Game Controller on which to apply the event
|
* @param gameController the game controller on which to apply the event.
|
||||||
* @return true if the player could draw the card, false otherwise
|
* @return {@code true} if the slot choice is handled successfully, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(GameController gameController) {
|
public boolean apply(GameController gameController) {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
|||||||
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
|
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.rmi.RemoteException;
|
import java.rmi.RemoteException;
|
||||||
import java.rmi.server.UnicastRemoteObject;
|
import java.rmi.server.UnicastRemoteObject;
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ import java.rmi.server.UnicastRemoteObject;
|
|||||||
* RMI client callback implementation of {@link IClientCallback}.
|
* RMI client callback implementation of {@link IClientCallback}.
|
||||||
* Receives notifications from the server and updates the client game model.
|
* Receives notifications from the server and updates the client game model.
|
||||||
*/
|
*/
|
||||||
public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCallback, Serializable {
|
public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCallback {
|
||||||
|
|
||||||
/** The client controller used to apply events and update the model */
|
/** The client controller used to apply events and update the model */
|
||||||
private final ClientController clientController;
|
private final ClientController clientController;
|
||||||
@@ -53,7 +52,7 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onAction(NetworkEvent event) throws RemoteException {
|
public void onAction(NetworkEvent event) throws RemoteException {
|
||||||
if(event.getIsError()) {
|
if(event.isError()) {
|
||||||
clientController.getView().showError(event.getErrorType(),event.toString());
|
clientController.getView().showError(event.getErrorType(),event.toString());
|
||||||
} else {
|
} else {
|
||||||
event.apply(clientController.getMiniModel());
|
event.apply(clientController.getMiniModel());
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class RMIClient implements IClient {
|
|||||||
private final int port;
|
private final int port;
|
||||||
private IGameServer stub;
|
private IGameServer stub;
|
||||||
private ClientController controller;
|
private ClientController controller;
|
||||||
private String myIP;
|
private String myIp;
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
@@ -35,13 +35,13 @@ public class RMIClient implements IClient {
|
|||||||
* @param controller the client controller associated with this RMI client.
|
* @param controller the client controller associated with this RMI client.
|
||||||
* @param host the hostname or IP address of the RMI server.
|
* @param host the hostname or IP address of the RMI server.
|
||||||
* @param port the port used to connect to the RMI registry.
|
* @param port the port used to connect to the RMI registry.
|
||||||
* @param myIP the IP address of the client.
|
* @param myIp the IP address of the client.
|
||||||
*/
|
*/
|
||||||
public RMIClient(ClientController controller, String host, int port, String myIP) {
|
public RMIClient(ClientController controller, String host, int port, String myIp) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.myIP = myIP;
|
this.myIp = myIp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -53,15 +53,15 @@ public class RMIClient implements IClient {
|
|||||||
* opening a second socket).
|
* opening a second socket).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ErrorType connect(String username, int preferredInt) {
|
public ErrorType connect(String username, int proposedNPlayers) {
|
||||||
try {
|
try {
|
||||||
System.setProperty("java.rmi.server.hostname", this.myIP);
|
System.setProperty("java.rmi.server.hostname", this.myIp);
|
||||||
Registry registry = LocateRegistry.getRegistry(host, port);
|
Registry registry = LocateRegistry.getRegistry(host, port);
|
||||||
this.stub = (IGameServer) registry.lookup("RMIGameServer");
|
this.stub = (IGameServer) registry.lookup("RMIGameServer");
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
|
||||||
ClientCallbackImpl callback = new ClientCallbackImpl(controller);
|
ClientCallbackImpl callback = new ClientCallbackImpl(controller);
|
||||||
ErrorType status = stub.joinGame(username, preferredInt, callback);
|
ErrorType status = stub.joinGame(username, proposedNPlayers, callback);
|
||||||
if(status==null)
|
if(status==null)
|
||||||
{
|
{
|
||||||
running = true;
|
running = true;
|
||||||
@@ -250,12 +250,12 @@ public class RMIClient implements IClient {
|
|||||||
* the keep-alive scheduler.
|
* the keep-alive scheduler.
|
||||||
*/
|
*/
|
||||||
public void notifyDisconnection() {
|
public void notifyDisconnection() {
|
||||||
|
running = false;
|
||||||
if (pingSender != null) pingSender.shutdownNow();
|
if (pingSender != null) pingSender.shutdownNow();
|
||||||
if (executor != null) executor.shutdownNow();
|
if (executor != null) executor.shutdownNow();
|
||||||
try {
|
try {
|
||||||
stub.disconnectPlayer(username);
|
stub.disconnectPlayer(username);
|
||||||
}
|
} catch (RemoteException e) {
|
||||||
catch (RemoteException e){
|
|
||||||
System.out.println("Error during remote disconnection");
|
System.out.println("Error during remote disconnection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ public interface IGameServer extends Remote {
|
|||||||
* to notify the corresponding RMI client.
|
* to notify the corresponding RMI client.
|
||||||
*
|
*
|
||||||
* @param username the username chosen by the player.
|
* @param username the username chosen by the player.
|
||||||
* @param preferredInt the preferred number of players for the game.
|
* @param preferredInt the desired number of players proposed by this client.
|
||||||
* @param callback the remote callback associated with the client.
|
* @param callback the remote callback associated with the client.
|
||||||
* @return {@code true} if the player joins the game successfully,
|
* @return {@code null} if the player joins successfully;
|
||||||
* {@code false} otherwise.
|
* an {@link it.polimi.ingsw.gc14.ErrorType} value describing the rejection otherwise.
|
||||||
* @throws RemoteException if an RMI communication error occurs.
|
* @throws RemoteException if an RMI communication error occurs.
|
||||||
*/
|
*/
|
||||||
ErrorType joinGame(String username, int preferredInt, IClientCallback callback) throws RemoteException;
|
ErrorType joinGame(String username, int preferredInt, IClientCallback callback) throws RemoteException;
|
||||||
@@ -96,5 +96,11 @@ public interface IGameServer extends Remote {
|
|||||||
*/
|
*/
|
||||||
void ping(String username) throws RemoteException;
|
void ping(String username) throws RemoteException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the server of a voluntary disconnection for the specified player.
|
||||||
|
*
|
||||||
|
* @param username the username of the player disconnecting.
|
||||||
|
* @throws RemoteException if an RMI communication error occurs.
|
||||||
|
*/
|
||||||
void disconnectPlayer(String username) throws RemoteException;
|
void disconnectPlayer(String username) throws RemoteException;
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import it.polimi.ingsw.gc14.LimitedMap;
|
|||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkConfig;
|
import it.polimi.ingsw.gc14.Network.NetworkConfig;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvents.DisconnectedPlayer;
|
import it.polimi.ingsw.gc14.Network.NetworkEvents.DisconnectedPlayer;
|
||||||
|
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
@@ -28,7 +29,7 @@ public class RMIHeartbeat {
|
|||||||
|
|
||||||
private String username = "";
|
private String username = "";
|
||||||
private final LimitedMap<String, Boolean> playerList;
|
private final LimitedMap<String, Boolean> playerList;
|
||||||
private final Map<String, ?> clients; // ConcurrentHashMap<String, IClientCallback>
|
private final Map<String, IClientCallback> clients;
|
||||||
private final BlockingQueue<NetworkEvent> actionQueue;
|
private final BlockingQueue<NetworkEvent> actionQueue;
|
||||||
|
|
||||||
/** Last time a ping was received from this client. */
|
/** Last time a ping was received from this client. */
|
||||||
@@ -53,7 +54,7 @@ public class RMIHeartbeat {
|
|||||||
public RMIHeartbeat(
|
public RMIHeartbeat(
|
||||||
String username,
|
String username,
|
||||||
LimitedMap<String, Boolean> playerList,
|
LimitedMap<String, Boolean> playerList,
|
||||||
Map<String, ?> clients,
|
Map<String, IClientCallback> clients,
|
||||||
BlockingQueue<NetworkEvent> actionQueue) {
|
BlockingQueue<NetworkEvent> actionQueue) {
|
||||||
|
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import it.polimi.ingsw.gc14.LimitedMap;
|
|||||||
import it.polimi.ingsw.gc14.Model.Game;
|
import it.polimi.ingsw.gc14.Model.Game;
|
||||||
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
|
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
|
||||||
import it.polimi.ingsw.gc14.Model.MiniModel;
|
import it.polimi.ingsw.gc14.Model.MiniModel;
|
||||||
|
import it.polimi.ingsw.gc14.Network.NetworkConfig;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
|
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
|
||||||
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
|
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
|
||||||
@@ -33,10 +34,10 @@ import java.util.stream.Collectors;
|
|||||||
* shared network event queue.
|
* shared network event queue.
|
||||||
*/
|
*/
|
||||||
public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
||||||
private String host;
|
private final String host;
|
||||||
private final GameController controller;
|
private final GameController controller;
|
||||||
private Registry registry;
|
private Registry registry;
|
||||||
private int nPort;
|
private final int nPort;
|
||||||
|
|
||||||
/** username → callback */
|
/** username → callback */
|
||||||
private final Map<String, IClientCallback> clients = new ConcurrentHashMap<>();
|
private final Map<String, IClientCallback> clients = new ConcurrentHashMap<>();
|
||||||
@@ -48,8 +49,8 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, RMIHeartbeat> watchdogs = new ConcurrentHashMap<>();
|
private final Map<String, RMIHeartbeat> watchdogs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
BlockingQueue<NetworkEvent> actionQueue;
|
private final BlockingQueue<NetworkEvent> actionQueue;
|
||||||
private LimitedMap<String, Boolean> playerList;
|
private final LimitedMap<String, Boolean> playerList;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,14 +81,17 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <p>After a successful join a {@link RMIHeartbeat} is created and
|
* <p>After a successful join an {@link RMIHeartbeat} watchdog is created and
|
||||||
* started for the new player — mirrors creating a {@code HeartbeatHandler} in
|
* started for the new player — mirrors creating a {@code HeartbeatHandler} in
|
||||||
* {@code TCPServer.acceptHeartbeat()}.
|
* {@code TCPServer.acceptHeartbeat()}.
|
||||||
|
*
|
||||||
|
* @return {@code null} on success; an {@link it.polimi.ingsw.gc14.ErrorType} value on rejection.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ErrorType joinGame(String username, int preferredInt, IClientCallback callback)
|
public ErrorType joinGame(String username, int preferredInt, IClientCallback callback)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
if (preferredInt < 2 || preferredInt > 5) return ErrorType.WRONG_PLAYER_NUMBER;
|
if (preferredInt < NetworkConfig.MIN_PLAYERS || preferredInt > NetworkConfig.MAX_PLAYERS)
|
||||||
|
return ErrorType.WRONG_PLAYER_NUMBER;
|
||||||
|
|
||||||
synchronized (controller) {
|
synchronized (controller) {
|
||||||
|
|
||||||
@@ -97,7 +101,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
System.out.println("Game Created With :"+preferredInt+" Players");
|
System.out.println("Game Created With :"+preferredInt+" Players");
|
||||||
}
|
}
|
||||||
if(controller.getModel().getCurrentState().getGameStage()!= GameStages.WAITING ) {
|
if(controller.getModel().getCurrentState().getGameStage()!= GameStages.WAITING ) {
|
||||||
if (!controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))) {
|
if (controller.getModel().getPlayers().stream().noneMatch(p -> p.getUserName().equals(username))) {
|
||||||
return ErrorType.GAME_ALREADY_STARTED;
|
return ErrorType.GAME_ALREADY_STARTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +133,12 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
System.out.println("Reconnected player: " + username);
|
System.out.println("Reconnected player: " + username);
|
||||||
startWatchdog(username);
|
startWatchdog(username);
|
||||||
Game game = controller.getModel();
|
Game game = controller.getModel();
|
||||||
callback.onGameInit(new MiniModel(game.getSlotMap(), game.getOrderLogicCard(), game.getCurrentState(), game.getPlayers(), game.getAvailableTotems(), game.getUpperListTribeCards(), game.getLowerListTribeCards(), game.getUpperListBuilding(), game.getLowerListBuilding(), game.getDisconnectedPlayers().entrySet().stream().filter(Map.Entry::getValue).map(x -> x.getKey().getUserName()).collect(Collectors.toCollection(ArrayList::new))));
|
callback.onGameInit(new MiniModel(
|
||||||
|
game.getSlotMap(), game.getOrderLogicCard(), game.getCurrentState(),
|
||||||
|
game.getPlayers(), game.getAvailableTotems(),
|
||||||
|
game.getUpperListTribeCards(), game.getLowerListTribeCards(),
|
||||||
|
game.getUpperListBuilding(), game.getLowerListBuilding(),
|
||||||
|
disconnectedUsernames(game)));
|
||||||
System.out.println("Model sent: " + username);
|
System.out.println("Model sent: " + username);
|
||||||
actionQueue.add(new ReconnectPlayer(username));
|
actionQueue.add(new ReconnectPlayer(username));
|
||||||
return null;
|
return null;
|
||||||
@@ -172,8 +181,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
*/
|
*/
|
||||||
public void notifyAll(NetworkEvent action){
|
public void notifyAll(NetworkEvent action){
|
||||||
for (Map.Entry<String, IClientCallback> entry : clients.entrySet()) {
|
for (Map.Entry<String, IClientCallback> entry : clients.entrySet()) {
|
||||||
if (!action.getIsError() ||
|
if (!action.isError() || action.getUsername().equals(entry.getKey())) {
|
||||||
(action.getIsError() && action.getUsername().equals(entry.getKey()))) {
|
|
||||||
try{
|
try{
|
||||||
entry.getValue().onAction(action);
|
entry.getValue().onAction(action);
|
||||||
}
|
}
|
||||||
@@ -300,7 +308,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
registry.rebind("RMIGameServer", this);
|
registry.rebind("RMIGameServer", this);
|
||||||
System.out.println("RMI Server started on port: " + nPort);
|
System.out.println("RMI Server started on port: " + nPort);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -319,7 +327,8 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
try {
|
try {
|
||||||
registry.unbind("RMIGameServer");
|
registry.unbind("RMIGameServer");
|
||||||
UnicastRemoteObject.unexportObject(this, true);
|
UnicastRemoteObject.unexportObject(this, true);
|
||||||
watchdogs.values().forEach(wd -> { /* watchdogs shut themselves down */ });
|
watchdogs.values().forEach(RMIHeartbeat::disconnect);
|
||||||
|
watchdogs.clear();
|
||||||
System.out.println("RMI Server stopped");
|
System.out.println("RMI Server stopped");
|
||||||
return true;
|
return true;
|
||||||
} catch (RemoteException | NotBoundException e) {
|
} catch (RemoteException | NotBoundException e) {
|
||||||
@@ -346,11 +355,20 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
|
|||||||
*
|
*
|
||||||
* @param username the username of the player to disconnect.
|
* @param username the username of the player to disconnect.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void disconnectPlayer(String username) {
|
public void disconnectPlayer(String username) {
|
||||||
RMIHeartbeat wd = watchdogs.get(username);
|
RMIHeartbeat wd = watchdogs.get(username);
|
||||||
if (wd != null) wd.disconnect();
|
if (wd != null) wd.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns usernames of players currently marked as disconnected in the given game. */
|
||||||
|
private static ArrayList<String> disconnectedUsernames(Game game) {
|
||||||
|
return game.getDisconnectedPlayers().entrySet().stream()
|
||||||
|
.filter(Map.Entry::getValue)
|
||||||
|
.map(e -> e.getKey().getUserName())
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,25 +22,25 @@ public class TCPClient implements IClient {
|
|||||||
private static final int PONG = 2;
|
private static final int PONG = 2;
|
||||||
|
|
||||||
/** Socket TCP */
|
/** Socket TCP */
|
||||||
Socket communicationSocket;
|
private Socket communicationSocket;
|
||||||
|
|
||||||
/** Input stream used receive objects from the server */
|
/** Input stream used receive objects from the server */
|
||||||
ObjectInputStream socketReceive;
|
private ObjectInputStream socketReceive;
|
||||||
|
|
||||||
/** Output stream used to send objects to the server */
|
/** Output stream used to send objects to the server */
|
||||||
ObjectOutputStream socketSend;
|
private ObjectOutputStream socketSend;
|
||||||
|
|
||||||
/** Client game's controller */
|
/** Client game's controller */
|
||||||
ClientController controller;
|
private ClientController controller;
|
||||||
|
|
||||||
/** IP address of the server to connect to */
|
/** IP address of the server to connect to */
|
||||||
String hostname;
|
private String hostname;
|
||||||
|
|
||||||
private boolean running;
|
private boolean running;
|
||||||
/** TCP port */
|
/** TCP port */
|
||||||
int mainPort;
|
private int mainPort;
|
||||||
|
|
||||||
int heartbeatPort;
|
private int heartbeatPort;
|
||||||
private Socket heartbeatSocket;
|
private Socket heartbeatSocket;
|
||||||
private OutputStream heartbeatOut;
|
private OutputStream heartbeatOut;
|
||||||
private InputStream heartbeatIn;
|
private InputStream heartbeatIn;
|
||||||
@@ -80,26 +80,27 @@ public class TCPClient implements IClient {
|
|||||||
try {
|
try {
|
||||||
if( socketReceive.readObject() instanceof AddPlayer x)
|
if( socketReceive.readObject() instanceof AddPlayer x)
|
||||||
{
|
{
|
||||||
if(x.getIsError())
|
if(x.isError())
|
||||||
return x.getErrorType();
|
return x.getErrorType();
|
||||||
}
|
}
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
return ErrorType.GENERIC_ERROR;
|
return ErrorType.GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
|
||||||
new Thread(this::receiveMessage, "tcp-reader").start();
|
new Thread(this::receiveMessage, "tcp-reader").start();
|
||||||
|
|
||||||
// Socket heartbeat
|
// heartbeat socket
|
||||||
this.heartbeatSocket = new Socket(hostname, heartbeatPort);
|
this.heartbeatSocket = new Socket(hostname, heartbeatPort);
|
||||||
this.heartbeatOut = heartbeatSocket.getOutputStream();
|
this.heartbeatOut = heartbeatSocket.getOutputStream();
|
||||||
this.heartbeatIn = heartbeatSocket.getInputStream();
|
this.heartbeatIn = heartbeatSocket.getInputStream();
|
||||||
|
|
||||||
// manda subito username per associare i due socket lato server
|
// send username immediately so server can associate the two sockets
|
||||||
new ObjectOutputStream(heartbeatSocket.getOutputStream()).writeObject(user);
|
new ObjectOutputStream(heartbeatSocket.getOutputStream()).writeObject(user);
|
||||||
heartbeatOut.flush();
|
heartbeatOut.flush();
|
||||||
new Thread(this::heartbeatLoop, "heartbeat").start();
|
new Thread(this::heartbeatLoop, "heartbeat").start();
|
||||||
|
|
||||||
running = true;
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -138,20 +139,17 @@ public class TCPClient implements IClient {
|
|||||||
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// pong ricevuto → server vivo
|
// pong received: server is alive
|
||||||
}
|
}
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
System.out.println("Server heartbeat timeout");
|
System.out.println("Server heartbeat timeout");
|
||||||
disconnect();
|
disconnect();
|
||||||
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if(running)
|
if (running) {
|
||||||
{
|
|
||||||
disconnect();
|
disconnect();
|
||||||
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
controller.getView().showError(ErrorType.SERVER_CRASHED, ErrorType.SERVER_CRASHED.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
sender.shutdownNow();
|
sender.shutdownNow();
|
||||||
}
|
}
|
||||||
@@ -170,7 +168,7 @@ public class TCPClient implements IClient {
|
|||||||
* Listens continuously for incoming objects from the server.
|
* Listens continuously for incoming objects from the server.
|
||||||
* - If the received object is a {@link NetworkEvent} flagged as an error, it is printed.
|
* - If the received object is a {@link NetworkEvent} flagged as an error, it is printed.
|
||||||
* - If the received object is a valid {@link NetworkEvent}, it is applied to the game controller.
|
* - If the received object is a valid {@link NetworkEvent}, it is applied to the game controller.
|
||||||
* - If the received object is a {@link Game} model, the controller's model is set.
|
* - If the received object is a {@link MiniModel}, the controller's model is set.
|
||||||
*/
|
*/
|
||||||
private void receiveMessage() {
|
private void receiveMessage() {
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -179,11 +177,12 @@ public class TCPClient implements IClient {
|
|||||||
try {
|
try {
|
||||||
read = socketReceive.readObject();
|
read = socketReceive.readObject();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
if (running) disconnect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read instanceof NetworkEvent event) {
|
if (read instanceof NetworkEvent event) {
|
||||||
if (event.getIsError()) {
|
if (event.isError()) {
|
||||||
if(event.getErrorType() == ErrorType.WRONG_ACTION) {
|
if(event.getErrorType() == ErrorType.WRONG_ACTION) {
|
||||||
controller.getView().showError(ErrorType.WRONG_ACTION,event.toString());
|
controller.getView().showError(ErrorType.WRONG_ACTION,event.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class ClientHandler implements Runnable {
|
|||||||
*/
|
*/
|
||||||
private final String username;
|
private final String username;
|
||||||
|
|
||||||
private boolean running ;
|
private volatile boolean running;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the username associated with this client.
|
* Returns the username associated with this client.
|
||||||
@@ -37,22 +37,22 @@ public class ClientHandler implements Runnable {
|
|||||||
private Socket clientSocket;
|
private Socket clientSocket;
|
||||||
|
|
||||||
/** Input stream used to receive objects from the client */
|
/** Input stream used to receive objects from the client */
|
||||||
public ObjectInputStream in;
|
private ObjectInputStream in;
|
||||||
|
|
||||||
/** Output stream used to send objects to the client */
|
/** Output stream used to send objects to the client */
|
||||||
public ObjectOutputStream out;
|
private ObjectOutputStream out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared list of all client handlers.
|
* Shared list of all client handlers.
|
||||||
* This handler removes itself from the list when disconnected.
|
* This handler removes itself from the list when disconnected.
|
||||||
*/
|
*/
|
||||||
List<ClientHandler> clientHandlers;
|
private List<ClientHandler> clientHandlers;
|
||||||
|
|
||||||
/** Maps each connected player's username to their connection state (true = connected). */
|
/** Maps each connected player's username to their connection state (true = connected). */
|
||||||
LimitedMap<String,Boolean> limitedMap;
|
private LimitedMap<String, Boolean> limitedMap;
|
||||||
|
|
||||||
/** Queue containing the events to be applied to the game model */
|
/** Queue containing the events to be applied to the game model */
|
||||||
BlockingQueue<NetworkEvent> actionQueue;
|
private BlockingQueue<NetworkEvent> actionQueue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,7 +87,7 @@ public class ClientHandler implements Runnable {
|
|||||||
try {
|
try {
|
||||||
while (running) {
|
while (running) {
|
||||||
NetworkEvent event = (NetworkEvent) in.readObject();
|
NetworkEvent event = (NetworkEvent) in.readObject();
|
||||||
if (!actionQueue.add(event)) {
|
if (!actionQueue.offer(event)) {
|
||||||
System.out.println("Error inserting action into queue");
|
System.out.println("Error inserting action into queue");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,14 +84,11 @@ public class HeartbeatHandler implements Runnable {
|
|||||||
startWatchdog();
|
startWatchdog();
|
||||||
try {
|
try {
|
||||||
while (running) {
|
while (running) {
|
||||||
int b = in.read(); // blocca finché non arriva un byte
|
int b = in.read(); // blocks until a byte arrives
|
||||||
if (b == -1) {
|
if (b == -1) {
|
||||||
synchronized (this)
|
disconnect();
|
||||||
{
|
break; // stream closed
|
||||||
out.write(-1);
|
|
||||||
}
|
}
|
||||||
disconnect(); break;
|
|
||||||
} // stream chiusa
|
|
||||||
if (b == PING) {
|
if (b == PING) {
|
||||||
lastReceivedTime = System.currentTimeMillis();
|
lastReceivedTime = System.currentTimeMillis();
|
||||||
out.write(PONG);
|
out.write(PONG);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import it.polimi.ingsw.gc14.Model.Game;
|
|||||||
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
|
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
|
||||||
import it.polimi.ingsw.gc14.Model.MiniModel;
|
import it.polimi.ingsw.gc14.Model.MiniModel;
|
||||||
import it.polimi.ingsw.gc14.Network.EventType;
|
import it.polimi.ingsw.gc14.Network.EventType;
|
||||||
|
import it.polimi.ingsw.gc14.Network.NetworkConfig;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
|
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvents.ReconnectPlayer;
|
import it.polimi.ingsw.gc14.Network.NetworkEvents.ReconnectPlayer;
|
||||||
@@ -34,47 +35,42 @@ public class TCPServer {
|
|||||||
/**
|
/**
|
||||||
* Main TCP port used for standard client-server communication.
|
* Main TCP port used for standard client-server communication.
|
||||||
*/
|
*/
|
||||||
int port;
|
private int port;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TCP port dedicated to heartbeat communication.
|
* TCP port dedicated to heartbeat communication.
|
||||||
*/
|
*/
|
||||||
int heartbeatPort;
|
private int heartbeatPort;
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of players that have successfully connected.
|
|
||||||
*/
|
|
||||||
int connectedPlayers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main server socket used to accept client connections.
|
* Main server socket used to accept client connections.
|
||||||
*/
|
*/
|
||||||
ServerSocket socketTCP;
|
private ServerSocket socketTCP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server socket used to accept heartbeat connections.
|
* Server socket used to accept heartbeat connections.
|
||||||
*/
|
*/
|
||||||
ServerSocket heartbeatSocketTCP;
|
private ServerSocket heartbeatSocketTCP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game controller used to manage the server-side game logic.
|
* Game controller used to manage the server-side game logic.
|
||||||
*/
|
*/
|
||||||
final GameController controller;
|
private final GameController controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue containing network events received from clients.
|
* Queue containing network events received from clients.
|
||||||
*/
|
*/
|
||||||
BlockingQueue<NetworkEvent> actionQueue;
|
private BlockingQueue<NetworkEvent> actionQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map storing the online/offline status of connected players.
|
* Map storing the online/offline status of connected players.
|
||||||
*/
|
*/
|
||||||
LimitedMap<String, Boolean> playerList;
|
private LimitedMap<String, Boolean> playerList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of active TCP client handlers.
|
* List of active TCP client handlers.
|
||||||
*/
|
*/
|
||||||
CopyOnWriteArrayList<ClientHandler> clientHandlers;
|
private CopyOnWriteArrayList<ClientHandler> clientHandlers;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,7 +95,6 @@ public class TCPServer {
|
|||||||
LimitedMap<String, Boolean> playerList) {
|
LimitedMap<String, Boolean> playerList) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.heartbeatPort = heartbeatPort;
|
this.heartbeatPort = heartbeatPort;
|
||||||
this.connectedPlayers = 0;
|
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.actionQueue = actionQueue;
|
this.actionQueue = actionQueue;
|
||||||
this.playerList = playerList;
|
this.playerList = playerList;
|
||||||
@@ -152,8 +147,8 @@ public class TCPServer {
|
|||||||
|
|
||||||
AddPlayer eventAddPlayer = (AddPlayer) event;
|
AddPlayer eventAddPlayer = (AddPlayer) event;
|
||||||
|
|
||||||
if (eventAddPlayer.getProposedNPlayer() < 2
|
if (eventAddPlayer.getProposedNPlayer() < NetworkConfig.MIN_PLAYERS
|
||||||
|| eventAddPlayer.getProposedNPlayer() > 5) {
|
|| eventAddPlayer.getProposedNPlayer() > NetworkConfig.MAX_PLAYERS) {
|
||||||
eventAddPlayer.setErrorType(ErrorType.WRONG_PLAYER_NUMBER);
|
eventAddPlayer.setErrorType(ErrorType.WRONG_PLAYER_NUMBER);
|
||||||
eventAddPlayer.setIsError(true);
|
eventAddPlayer.setIsError(true);
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
@@ -172,7 +167,7 @@ public class TCPServer {
|
|||||||
System.out.println("Game Created With :"+eventAddPlayer.getProposedNPlayer()+" Players");
|
System.out.println("Game Created With :"+eventAddPlayer.getProposedNPlayer()+" Players");
|
||||||
}
|
}
|
||||||
if(controller.getModel().getCurrentState().getGameStage()!= GameStages.WAITING ) {
|
if(controller.getModel().getCurrentState().getGameStage()!= GameStages.WAITING ) {
|
||||||
if (!controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))) {
|
if (controller.getModel().getPlayers().stream().noneMatch(p -> p.getUserName().equals(username))) {
|
||||||
eventAddPlayer.setErrorType(ErrorType.GAME_ALREADY_STARTED);
|
eventAddPlayer.setErrorType(ErrorType.GAME_ALREADY_STARTED);
|
||||||
eventAddPlayer.setIsError(true);
|
eventAddPlayer.setIsError(true);
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
@@ -185,29 +180,12 @@ public class TCPServer {
|
|||||||
if (controller.addPlayer(username)) {
|
if (controller.addPlayer(username)) {
|
||||||
playerList.put(username, true);
|
playerList.put(username, true);
|
||||||
System.out.println("Accepted player: " + username);
|
System.out.println("Accepted player: " + username);
|
||||||
ClientHandler handler = new ClientHandler(
|
|
||||||
username,
|
|
||||||
clientSocket,
|
|
||||||
clientSend,
|
|
||||||
clientReceive,
|
|
||||||
clientHandlers,
|
|
||||||
playerList,
|
|
||||||
actionQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
pendingHeartbeat.put(username, handler);
|
ClientHandler handler = createAndRegisterHandler(
|
||||||
|
username, clientSocket, clientSend, clientReceive);
|
||||||
Thread thread = new Thread(handler);
|
new Thread(handler).start();
|
||||||
thread.start();
|
|
||||||
|
|
||||||
clientHandlers.add(handler);
|
|
||||||
connectedPlayers++;
|
|
||||||
continue;
|
continue;
|
||||||
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
eventAddPlayer.setErrorType(ErrorType.USERNAME_ALREADY_USED);
|
eventAddPlayer.setErrorType(ErrorType.USERNAME_ALREADY_USED);
|
||||||
eventAddPlayer.setIsError(true);
|
eventAddPlayer.setIsError(true);
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
@@ -217,67 +195,31 @@ public class TCPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!playerList.containsKey(username)) {
|
if (!playerList.containsKey(username)) {
|
||||||
playerList.put(username, true);
|
playerList.put(username, true);
|
||||||
System.out.println("(After crash)Reconnected player: " + username);
|
System.out.println("(After crash)Reconnected player: " + username);
|
||||||
ClientHandler handler = new ClientHandler(
|
|
||||||
username,
|
|
||||||
clientSocket,
|
|
||||||
clientSend,
|
|
||||||
clientReceive,
|
|
||||||
clientHandlers,
|
|
||||||
playerList,
|
|
||||||
actionQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
pendingHeartbeat.put(username, handler);
|
ClientHandler handler = createAndRegisterHandler(
|
||||||
|
username, clientSocket, clientSend, clientReceive);
|
||||||
Thread thread = new Thread(handler);
|
new Thread(handler).start();
|
||||||
thread.start();
|
} else if (!playerList.get(username)) {
|
||||||
|
|
||||||
clientHandlers.add(handler);
|
|
||||||
connectedPlayers++;
|
|
||||||
}
|
|
||||||
// reconnect a previously disconnected player
|
// reconnect a previously disconnected player
|
||||||
else{
|
|
||||||
if (!playerList.get(username)) {
|
|
||||||
|
|
||||||
playerList.put(username, true);
|
playerList.put(username, true);
|
||||||
System.out.println("Reconnected player: " + username);
|
System.out.println("Reconnected player: " + username);
|
||||||
ClientHandler handler = new ClientHandler(
|
|
||||||
username,
|
|
||||||
clientSocket,
|
|
||||||
clientSend,
|
|
||||||
clientReceive,
|
|
||||||
clientHandlers,
|
|
||||||
playerList,
|
|
||||||
actionQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
pendingHeartbeat.put(username, handler);
|
ClientHandler handler = createAndRegisterHandler(
|
||||||
|
username, clientSocket, clientSend, clientReceive);
|
||||||
Game game = controller.getModel();
|
Game game = controller.getModel();
|
||||||
handler.notifyMiniModel(new MiniModel(
|
handler.notifyMiniModel(new MiniModel(
|
||||||
game.getSlotMap(),
|
game.getSlotMap(), game.getOrderLogicCard(),
|
||||||
game.getOrderLogicCard(),
|
game.getCurrentState(), game.getPlayers(),
|
||||||
game.getCurrentState(),
|
|
||||||
game.getPlayers(),
|
|
||||||
game.getAvailableTotems(),
|
game.getAvailableTotems(),
|
||||||
game.getUpperListTribeCards(), game.getLowerListTribeCards(), game.getUpperListBuilding(), game.getLowerListBuilding(), game.getDisconnectedPlayers().entrySet().stream().filter(Map.Entry::getValue).map(x -> x.getKey().getUserName()).collect(Collectors.toCollection(ArrayList::new))
|
game.getUpperListTribeCards(), game.getLowerListTribeCards(),
|
||||||
));
|
game.getUpperListBuilding(), game.getLowerListBuilding(),
|
||||||
|
disconnectedUsernames(game)));
|
||||||
Thread thread = new Thread(handler);
|
new Thread(handler).start();
|
||||||
thread.start();
|
|
||||||
|
|
||||||
clientHandlers.add(handler);
|
|
||||||
connectedPlayers++;
|
|
||||||
actionQueue.add(new ReconnectPlayer(username));
|
actionQueue.add(new ReconnectPlayer(username));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
eventAddPlayer.setErrorType(ErrorType.USER_ALREADY_CONNECTED);
|
eventAddPlayer.setErrorType(ErrorType.USER_ALREADY_CONNECTED);
|
||||||
eventAddPlayer.setIsError(true);
|
eventAddPlayer.setIsError(true);
|
||||||
clientSend.writeObject(eventAddPlayer);
|
clientSend.writeObject(eventAddPlayer);
|
||||||
@@ -285,7 +227,6 @@ public class TCPServer {
|
|||||||
System.out.println("Invalid parameters. Connection terminated.");
|
System.out.println("Invalid parameters. Connection terminated.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -340,7 +281,7 @@ public class TCPServer {
|
|||||||
*/
|
*/
|
||||||
public void notifyAll(NetworkEvent event) {
|
public void notifyAll(NetworkEvent event) {
|
||||||
clientHandlers.forEach(h -> {
|
clientHandlers.forEach(h -> {
|
||||||
if (!event.getIsError() || event.getUsername().equals(h.getUsername())) {
|
if (!event.isError() || event.getUsername().equals(h.getUsername())) {
|
||||||
h.notifyEvent(event);
|
h.notifyEvent(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -354,4 +295,28 @@ public class TCPServer {
|
|||||||
public void notifyAll(MiniModel model) {
|
public void notifyAll(MiniModel model) {
|
||||||
clientHandlers.forEach(h -> h.notifyMiniModel(model));
|
clientHandlers.forEach(h -> h.notifyMiniModel(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link ClientHandler}, registers it in {@code pendingHeartbeat}
|
||||||
|
* and {@code clientHandlers}, but does NOT start its thread — callers start
|
||||||
|
* the thread after any extra setup (e.g. sending a model snapshot).
|
||||||
|
*/
|
||||||
|
private ClientHandler createAndRegisterHandler(String username,
|
||||||
|
Socket socket,
|
||||||
|
ObjectOutputStream out,
|
||||||
|
ObjectInputStream in) {
|
||||||
|
ClientHandler handler = new ClientHandler(
|
||||||
|
username, socket, out, in, clientHandlers, playerList, actionQueue);
|
||||||
|
pendingHeartbeat.put(username, handler);
|
||||||
|
clientHandlers.add(handler);
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns usernames of players currently marked as disconnected in the given game. */
|
||||||
|
private static ArrayList<String> disconnectedUsernames(Game game) {
|
||||||
|
return game.getDisconnectedPlayers().entrySet().stream()
|
||||||
|
.filter(Map.Entry::getValue)
|
||||||
|
.map(e -> e.getKey().getUserName())
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user