diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java index cc3e337..bca2e27 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Server/RMIServer.java @@ -30,7 +30,7 @@ import java.rmi.*; */ public class RMIServer extends UnicastRemoteObject implements IGameServer { private String host; - private GameController controller; + private final GameController controller; private Registry registry; private int nPort; @@ -105,23 +105,13 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { System.out.println("(After crash)Reconnected player: " + username); return true; } - if (playerList.containsKey(username) && !playerList.get(username)) { - playerList.put(username, true); - clients.put(username, callback); - System.out.println("Reconnected player: " + username); - startWatchdog(username); - Game game = controller.getModel(); - callback.onGameInit(new MiniModel(game.getSlotMap(), game.orderLogicCard,game.getCurrentState(),game.getPlayers(),game.getAvailableTotems(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding())); - System.out.println("Model sent: " + username); - actionQueue.add(new ReconnectPlayer(username)); - return true; - } } else { if (playerList.isEmpty()) { controller.setModel(new Game(preferredInt)); playerList.setLimit(preferredInt); + System.out.println("Game Created With :"+preferredInt+" Players"); } if (controller.addPlayer(username)) { clients.put(username, callback); @@ -130,18 +120,17 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer { System.out.println("Accepted player: " + username); return true; } - // Reconnection: player was offline - if (playerList.containsKey(username) && !playerList.get(username)) { - playerList.put(username, true); - clients.put(username, callback); - System.out.println("Reconnected player: " + username); - startWatchdog(username); - Game game = controller.getModel(); - callback.onGameInit(new MiniModel(game.getSlotMap(), game.orderLogicCard,game.getCurrentState(),game.getPlayers(),game.getAvailableTotems(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding())); - System.out.println("Model sent: " + username); - actionQueue.add(new ReconnectPlayer(username)); - return true; - } + } + if (playerList.containsKey(username) && !playerList.get(username)) { + playerList.put(username, true); + clients.put(username, callback); + System.out.println("Reconnected player: " + username); + startWatchdog(username); + Game game = controller.getModel(); + callback.onGameInit(new MiniModel(game.getSlotMap(), game.orderLogicCard,game.getCurrentState(),game.getPlayers(),game.getAvailableTotems(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding())); + System.out.println("Model sent: " + username); + actionQueue.add(new ReconnectPlayer(username)); + return true; } return false; } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/TCPServer.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/TCPServer.java index fd73764..9c618ef 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/TCPServer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Server/TCPServer.java @@ -179,12 +179,11 @@ public class TCPServer { synchronized (controller) { String username = eventAddPlayer.getUsername(); - + //reconnect players after a server crash if (serverCrashed) { if (controller.getModel().getPlayers().stream() .anyMatch(p -> p.getUserName().equals(username)) && !playerList.containsKey(username)) { - playerList.put(username, true); System.out.println("(After crash)Reconnected player: " + username); @@ -206,54 +205,18 @@ public class TCPServer { clientHandlers.add(handler); connectedPlayers++; + return; - } else if (playerList.containsKey(username) - && !playerList.get(username)) { - - playerList.put(username, true); - System.out.println("Reconnected player: " + username); - - ClientHandler handler = new ClientHandler( - username, - clientSocket, - clientSend, - clientReceive, - clientHandlers, - playerList, - actionQueue - ); - - clientSocket.getOutputStream().write(1); - pendingHeartbeat.put(username, handler); - - Game game = controller.getModel(); - handler.notifyMiniModel(new MiniModel( - game.getSlotMap(), - game.orderLogicCard, - game.getCurrentState(), - game.getPlayers(), - game.getAvailableTotems(), - game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding() - )); - - Thread thread = new Thread(handler); - thread.start(); - - clientHandlers.add(handler); - connectedPlayers++; - actionQueue.add(new ReconnectPlayer(username)); - - } else { - clientSocket.getOutputStream().write(-1); - clientSocket.close(); - System.out.println("Player could not be added. Connection terminated."); } - } else { + } + //manages a new player adding + else { if (playerList.isEmpty()) { Game model = new Game(eventAddPlayer.getProposedNPlayer()); controller.setModel(model); playerList.setLimit(eventAddPlayer.getProposedNPlayer()); + System.out.println("Game Created With :"+eventAddPlayer.getProposedNPlayer()+" Players"); } if (controller.addPlayer(username)) { @@ -278,52 +241,55 @@ public class TCPServer { clientHandlers.add(handler); connectedPlayers++; + return; - } else if (playerList.containsKey(username) - && !playerList.get(username)) { - - playerList.put(username, true); - System.out.println("Reconnected player: " + username); - - ClientHandler handler = new ClientHandler( - username, - clientSocket, - clientSend, - clientReceive, - clientHandlers, - playerList, - actionQueue - ); - - clientSocket.getOutputStream().write(1); - pendingHeartbeat.put(username, handler); - - Game game = controller.getModel(); - handler.notifyMiniModel(new MiniModel( - game.getSlotMap(), - game.orderLogicCard, - game.getCurrentState(), - game.getPlayers(), - game.getAvailableTotems(), - game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding() - - )); - - Thread thread = new Thread(handler); - thread.start(); - - clientHandlers.add(handler); - connectedPlayers++; - actionQueue.add(new ReconnectPlayer(username)); - - } else { - clientSocket.getOutputStream().write(-1); - clientSocket.close(); - System.out.println("Player could not be added. Connection terminated."); } } + //reconnect a previously disconnected player + if (playerList.containsKey(username) + && !playerList.get(username)) { + + playerList.put(username, true); + System.out.println("Reconnected player: " + username); + + ClientHandler handler = new ClientHandler( + username, + clientSocket, + clientSend, + clientReceive, + clientHandlers, + playerList, + actionQueue + ); + + clientSocket.getOutputStream().write(1); + pendingHeartbeat.put(username, handler); + + Game game = controller.getModel(); + handler.notifyMiniModel(new MiniModel( + game.getSlotMap(), + game.orderLogicCard, + game.getCurrentState(), + game.getPlayers(), + game.getAvailableTotems(), + game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding() + )); + + Thread thread = new Thread(handler); + thread.start(); + + clientHandlers.add(handler); + connectedPlayers++; + actionQueue.add(new ReconnectPlayer(username)); + + } else { + clientSocket.getOutputStream().write(-1); + clientSocket.close(); + System.out.println("Player could not be added. Connection terminated."); + } } + } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } diff --git a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java index a986bd6..2138468 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java +++ b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java @@ -52,7 +52,7 @@ public class ServerLauncher { BlockingQueue actionQueue; /** Game controller. Used to apply events */ - GameController gameController; + final GameController gameController; /** Server RMI. Handles RMI clients */ RMIServer serverRMI; @@ -106,8 +106,10 @@ public class ServerLauncher { */ public boolean doFirstEvent() throws InterruptedException { NetworkEvent event = actionQueue.take(); - if(gameController.getModel()!=null && !gameController.getModel().getCurrentState().equals(GameStages.ENDED)) + //Verify that the model exist and if it exists that's not ended + if(gameController.getModel()!=null && gameController.getModel().getCurrentState().getGameStage()!=GameStages.ENDED) { + //if there is only one player ignore every event different by reconnection if(disconnectionTimer!=null && event.getEventType() != EventType.RECONNECT_PLAYER) { event.setIsError(true); @@ -115,16 +117,24 @@ public class ServerLauncher { serverTCP.notifyAll(event); return false; } + + //Cancel the timer if another player is reconnected , so there are more than one player if (event.getEventType() == EventType.RECONNECT_PLAYER && disconnectionTimer != null && !disconnectionTimer.isDone()) { disconnectionTimer.cancel(false); disconnectionTimer = null; } + int roundPrev=gameController.getModel().getCurrentState().getRound(); synchronized(gameController){ + //applies the event and set if is an error event.setIsError(!event.apply(gameController)); Game game=gameController.getModel(); + //if the event wasn't an error , it will be sent to players if(!event.getIsError()) { + if(!this.gameSave() ){ + System.out.println("\n!!! Save failed !!!\n"); + } if(event.getEventType().equals(EventType.DISCONNECTED_PLAYER)&& game.getCurrentState().getGameStage().equals(GameStages.WAITING)) { playerList.remove(event.getUsername()); @@ -132,11 +142,43 @@ public class ServerLauncher { event.setData(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(), game.getPlayers()); if (event.getEventType().equals(EventType.TOTEM_CHOICE)) { ((TotemChoice) event).setAvailableTotems(gameController.getModel().getAvailableTotems()); - } else if (event.getEventType().equals(EventType.DISCONNECTED_PLAYER) && game.getCurrentState().equals(GameStages.WAITING)) { + } else if (event.getEventType().equals(EventType.DISCONNECTED_PLAYER) && game.getCurrentState().getGameStage().equals(GameStages.WAITING)) { playerList.remove(event.getUsername()); } } - if(game.getCurrentState().getGameStage() == GameStages.ENDED){ + //if there is only one player the game will be suspended and starts the forfeit timer + if (event.getEventType().equals(EventType.DISCONNECTED_PLAYER) && playerList.values().stream().filter(x -> x).count() == 1&& game.getCurrentState().getGameStage() != GameStages.ENDED) { + if (disconnectionTimer != null && !disconnectionTimer.isDone()) { + disconnectionTimer.cancel(false); + } + //schedule endgame for forfeit + disconnectionTimer = timerExecutor.schedule(() -> { + game.EndGameForFeit(); + serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); + serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); + System.out.println("Timer expired: no player reconnected in 60s."); + for(Map.Entry entry:playerList.entrySet()){ + if(!entry.getValue()) + playerList.remove(entry.getKey()); + } + if(!this.deleteSave()){ + System.out.println("\n!!! Couldn't delete save !!!\n"); + } + disconnectionTimer = null; + }, 1, TimeUnit.MINUTES); + } + //if the round is changed send a new next round event , the previous event is ignored and directly sent the next round(also upper and lower lists updated) + if(game.getCurrentState().getRound()!=roundPrev) + { + ApplyNextRound nextRound=new ApplyNextRound(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayers(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding()); + serverRMI.notifyAll(nextRound); + serverTCP.notifyAll(nextRound); + } + // if the game ends after the event, delete the game. await that all players are disconnected and then create a new game + else if(game.getCurrentState().getGameStage().equals(GameStages.ENDED)) + { + serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); + serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); if(!this.deleteSave()){ System.out.println("\n!!! Couldn't delete save !!!\n"); } @@ -147,48 +189,26 @@ public class ServerLauncher { serverRMI.setServerCrashed(false); serverTCP.setServerCrashed(false); } - else if(!this.gameSave() ){ - System.out.println("\n!!! Save failed !!!\n"); + //notify the event + else { + serverRMI.notifyAll(event); + serverTCP.notifyAll(event); } } - serverRMI.notifyAll(event); - serverTCP.notifyAll(event); - if(game.getCurrentState().getRound()!=roundPrev) - { - ApplyNextRound nextRound=new ApplyNextRound(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayers(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding()); - serverRMI.notifyAll(nextRound); - serverTCP.notifyAll(nextRound); - } - else if(game.getCurrentState().getGameStage().equals(GameStages.ENDED)) - { - serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); - serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); - } - if (event.getEventType().equals(EventType.DISCONNECTED_PLAYER) && playerList.values().stream().filter(x -> x).count() == 1&& game.getCurrentState().getGameStage() != GameStages.ENDED) { - if (disconnectionTimer != null && !disconnectionTimer.isDone()) { - disconnectionTimer.cancel(false); - } - disconnectionTimer = timerExecutor.schedule(() -> { - game.EndGameForFeit(); - serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); - serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); - System.out.println("Timer expired: no player reconnected in 60s."); - if(!this.deleteSave()){ - System.out.println("\n!!! Couldn't delete save !!!\n"); - } - }, 1, TimeUnit.MINUTES); - } return !event.getIsError(); } } else{ + // removes disconneted players when the game is ended if(event.getEventType().equals(EventType.DISCONNECTED_PLAYER)) { playerList.remove(event.getUsername()); if(playerList.isEmpty()) { gameController.setModel(null); + System.out.println("\n!!! Player list is now empty, ready for a new game init !!!\n"); } + return true; } return false; } @@ -253,12 +273,12 @@ public class ServerLauncher { MiniModel miniModel; synchronized (gameController) { Game game = gameController.getModel(); - miniModel= new MiniModel(game.getSlotMap(), game.orderLogicCard,game.getCurrentState(),game.getPlayers(), new ArrayList<>(List.of(Totems.values())),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding()); + miniModel= new MiniModel(game.getSlotMap(), game.orderLogicCard,game.getCurrentState(),game.getPlayers(), game.getAvailableTotems(),game.getUpperListTribeCards(),game.getLowerListTribeCards(),game.getUpperListBuilding(),game.getLowerListBuilding()); } serverRMI.notifyAll(miniModel); serverTCP.notifyAll(miniModel); view = new TUI(miniModel); - view.fullRender(); + view.render(); }).start(); }); new Thread(()-> { @@ -290,10 +310,10 @@ public class ServerLauncher { while (true) { try{ this.doFirstEvent(); - if(view!=null) - { - view.fullRender(); - } +// if(view!=null) +// { +// view.fullRender(); +// } } catch(InterruptedException e){ Thread.currentThread().interrupt();