diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 1f0d743..b10876f 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -4,6 +4,7 @@ + \ No newline at end of file diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index a45c144..7d36641 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -104,6 +104,7 @@ it.polimi.ingsw.gc14.ClientLauncherGUI + @@ -112,6 +113,7 @@ META-INF/*.SF META-INF/*.DSA META-INF/*.RSA + META-INF/versions/9/module-info.class diff --git a/pom.xml b/pom.xml index 4699c9f..428f8b5 100644 --- a/pom.xml +++ b/pom.xml @@ -158,6 +158,7 @@ it.polimi.ingsw.gc14.ClientLauncherGUI + @@ -166,6 +167,7 @@ META-INF/*.SF META-INF/*.DSA META-INF/*.RSA + META-INF/versions/9/module-info.class diff --git a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java index 3f9e93a..35db3ca 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherGUI.java @@ -15,7 +15,7 @@ public class ClientLauncherGUI { public static class GUIApp extends Application { @Override public void start(Stage stage) throws Exception { - GUI view = new GUI(stage); + GUI view = new GUI(); ClientController controller = new ClientController(view); view.setController(controller); view.start(stage); diff --git a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java index 97cb658..13edbd4 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java +++ b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java @@ -38,7 +38,6 @@ public class ClientController { public ClientController(IView view) { this.view = view; this.client = null; - this.miniModel = new MiniModel(); } /** diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java b/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java index fad51b1..b8326bd 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/GamePackage/GameStages.java @@ -1,46 +1,69 @@ package it.polimi.ingsw.gc14.Model.GamePackage; - /** +/** * Represents the possible stages of a game. */ public enum GameStages { + /** * Stage in which the game is waiting for players to join. */ - WAITING, + WAITING("Waiting"), /** * Stage in which players choose their totems. */ - TOTEM_CHOICE, + TOTEM_CHOICE("Totem"), /** * Stage in which players select their action slots. */ - SLOT_CHOICE, + SLOT_CHOICE("Slot"), /** * Stage in which the mandatory actions associated with the chosen slots are resolved. */ - RES_ACTIONS, + RES_ACTIONS("Actions"), /** * Stage in which an optional card effect can be resolved. */ - OPT_CARD_E, + OPT_CARD_E("Card Effect"), /** * Stage in which an event card is being resolved. */ - RES_EVENT, + RES_EVENT("Event"), /** * Stage in which end-of-round or end-of-game operations are processed. */ - ENDING, + ENDING("Ending"), /** * Stage indicating that the game has ended. */ - ENDED - } + ENDED("Ended"); + + /** The human-readable name of this stage, used in {@link #toString()}. */ + private final String displayName; + + /** + * Constructs a {@code GameStages} value with the given display name. + * + * @param displayName the human-readable label for this stage + */ + GameStages(String displayName) { + this.displayName = displayName; + } + + /** + * Returns the human-readable name of this stage. + * + * @return the display name (e.g. {@code "Slot"} for {@code SLOT_CHOICE}) + */ + @Override + public String toString() { + return displayName; + } +} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/AddPlayer.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/AddPlayer.java index c61f28d..7809819 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/AddPlayer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/AddPlayer.java @@ -46,12 +46,14 @@ public class AddPlayer extends NetworkEvent implements Serializable { //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; + synchronized (miniModel) { + if (isError) + return false; + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java index 9760b4e..322d0bd 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ApplyNextRound.java @@ -59,15 +59,17 @@ public class ApplyNextRound extends NetworkEvent implements Serializable{ } public boolean apply(MiniModel miniModel) { - miniModel.setSlotPlayerMap(slotPlayerMap); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setPlayers(players); - miniModel.upperListTribeCards=upperListTribeCards; - miniModel.lowerListTribeCards=lowerListTribeCards; - miniModel.upperListBuildingCards=upperListBuildingCards; - miniModel.lowerListBuildingCards=lowerListBuildingCards; - return true; + synchronized (miniModel) { + miniModel.setSlotPlayerMap(slotPlayerMap); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setPlayers(players); + miniModel.upperListTribeCards = upperListTribeCards; + miniModel.lowerListTribeCards = lowerListTribeCards; + miniModel.upperListBuildingCards = upperListBuildingCards; + miniModel.lowerListBuildingCards = lowerListBuildingCards; + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DisconnectedPlayer.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DisconnectedPlayer.java index e73a323..1bcfd53 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DisconnectedPlayer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DisconnectedPlayer.java @@ -33,16 +33,17 @@ public class DisconnectedPlayer extends NetworkEvent implements Serializable{ //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - if(miniModel!=null) - { - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); + synchronized (miniModel) { + if (isError) + return false; + if (miniModel != null) { + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + } + return true; } - return true; } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerBuildingCard.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerBuildingCard.java index d0cfb5a..03a04ea 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerBuildingCard.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerBuildingCard.java @@ -39,16 +39,17 @@ public class DrawLowerBuildingCard extends NetworkEvent implements Serializable //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - - miniModel.lowerListBuildingCards.remove(pos); - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; + synchronized (miniModel) { + if (isError) + return false; + miniModel.lowerListBuildingCards.remove(pos); + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerTribeCard.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerTribeCard.java index b9b7394..b36f9d1 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerTribeCard.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawLowerTribeCard.java @@ -38,16 +38,17 @@ public class DrawLowerTribeCard extends NetworkEvent implements Serializable{ //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - - miniModel.lowerListTribeCards.remove(pos); - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; + synchronized (miniModel) { + if (isError) + return false; + miniModel.lowerListTribeCards.remove(pos); + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperBuildingCard.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperBuildingCard.java index 147e7d5..e631ce0 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperBuildingCard.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperBuildingCard.java @@ -39,15 +39,16 @@ public class DrawUpperBuildingCard extends NetworkEvent implements Serializable //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - - miniModel.upperListBuildingCards.remove(pos); - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; + synchronized (miniModel) { + if (isError) + return false; + miniModel.upperListBuildingCards.remove(pos); + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperTribeCard.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperTribeCard.java index 94ee411..9bf23f4 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperTribeCard.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/DrawUpperTribeCard.java @@ -38,15 +38,16 @@ public class DrawUpperTribeCard extends NetworkEvent implements Serializable{ //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - miniModel.upperListTribeCards.remove(pos); - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; - + synchronized (miniModel) { + if (isError) + return false; + miniModel.upperListTribeCards.remove(pos); + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java index d42cfed..d2722ae 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/EndedGame.java @@ -48,12 +48,14 @@ public class EndedGame extends NetworkEvent implements Serializable{ } public boolean apply(MiniModel miniModel) { - miniModel.setSlotPlayerMap(slotPlayerMap); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setPlayers(players); - miniModel.setStandingPlayers(players); - return true; + synchronized (miniModel) { + miniModel.setSlotPlayerMap(slotPlayerMap); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setPlayers(players); + miniModel.setStandingPlayers(players); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java index 1ef0305..8cfd706 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/ReconnectPlayer.java @@ -45,16 +45,18 @@ public class ReconnectPlayer extends NetworkEvent implements Serializable { */ @Override public boolean apply(MiniModel miniModel) { - if (isError) - return false; + synchronized (miniModel) { + if (isError) + return false; - if (miniModel != null) { - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); + if (miniModel != null) { + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + } + + return true; } - - return true; } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SkipTurn.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SkipTurn.java index a0e84ae..3358948 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SkipTurn.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SkipTurn.java @@ -33,14 +33,15 @@ public class SkipTurn extends NetworkEvent implements Serializable{ //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; - + synchronized (miniModel) { + if (isError) + return false; + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SlotChoice.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SlotChoice.java index 612a9c1..c82853c 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SlotChoice.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/SlotChoice.java @@ -39,14 +39,15 @@ public class SlotChoice extends NetworkEvent implements Serializable { //TODO @Override public boolean apply(MiniModel miniModel){ - if(isError) - return false; - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - return true; - + synchronized (miniModel) { + if (isError) + return false; + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + return true; + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java index fe0aad0..a9c3119 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/NetworkEvents/TotemChoice.java @@ -69,14 +69,16 @@ public class TotemChoice extends NetworkEvent implements Serializable { */ @Override public boolean apply(MiniModel miniModel) { - if (isError) - return false; + synchronized (miniModel) { + if (isError) + return false; - miniModel.setPlayers(playerList); - miniModel.setOrderLogicCard(orderLogicCard); - miniModel.setCurrentState(currentState); - miniModel.setSlotPlayerMap(slotPlayerMap); - miniModel.setAvailableTotems(availableTotems); - return true; + miniModel.setPlayers(playerList); + miniModel.setOrderLogicCard(orderLogicCard); + miniModel.setCurrentState(currentState); + miniModel.setSlotPlayerMap(slotPlayerMap); + miniModel.setAvailableTotems(availableTotems); + return true; + } } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java index 74aa52b..e026eaa 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java @@ -5,6 +5,7 @@ import it.polimi.ingsw.gc14.Model.Game; import it.polimi.ingsw.gc14.Model.MiniModel; import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback; +import javafx.application.Platform; import java.io.Serializable; import java.rmi.RemoteException; @@ -53,12 +54,12 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa */ @Override public void onAction(NetworkEvent event) throws RemoteException { - synchronized (clientController) { - if(event.getIsError()) { - clientController.view.showError(event.toString()); - } else { - clientController.view.applyAndRender(event); - } + if(event.getIsError()) { + clientController.view.showError(event.toString()); + } else { + event.apply(clientController.miniModel); + clientController.view.render(); } + } } 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/Client/TCPClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java index 28598d4..67ae202 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java @@ -6,6 +6,7 @@ import it.polimi.ingsw.gc14.Model.MiniModel; import it.polimi.ingsw.gc14.Network.IClient; import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvents.*; +import javafx.application.Platform; import java.io.*; import java.net.*; @@ -163,14 +164,13 @@ public class TCPClient implements IClient { if (event.getIsError()) { controller.view.showError(event.toString()); } else { - controller.view.applyAndRender(event); + event.apply(controller.miniModel); + controller.view.render(); } } else if (read instanceof MiniModel model) { - synchronized (controller) { - controller.setModel(model); - controller.view.render(); - } + controller.setModel(model); + controller.view.render(); } } catch (ClassNotFoundException e) { 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(); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java index f6a9197..550d582 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java @@ -45,12 +45,10 @@ public class GUI extends Application implements IView { private ClientController controller; - public GUI(Stage stage) { - this.primaryStage = stage; - } @Override public void start(Stage stage) throws Exception { + this.primaryStage = stage; loaderLogin = new FXMLLoader(getClass().getResource("/GUIScene/login.fxml")); loginScene = new Scene(loaderLogin.load()); controllerLogin = loaderLogin.getController(); @@ -73,7 +71,7 @@ public class GUI extends Application implements IView { loaderLeaderboard = new FXMLLoader(getClass().getResource("/GUIScene/standing.fxml")); leaderboardScene = new Scene(loaderLeaderboard.load()); controllerLeaderboard = loaderLeaderboard.getController(); - controllerLeaderboard.setController(controller); + controllerLeaderboard.setController(controller,primaryStage,loginScene); mainScene = new Scene(loaderMain.load()); controllerMain = loaderMain.getController(); @@ -81,10 +79,7 @@ public class GUI extends Application implements IView { showLogin(); - stage.setTitle("Mesos"); - primaryStage.setMaximized(true); - primaryStage.setMinWidth(1583); - primaryStage.setMinHeight(734); + primaryStage.setTitle("Mesos"); primaryStage.setOnCloseRequest(e -> { Platform.exit(); System.exit(0); @@ -106,48 +101,29 @@ public class GUI extends Application implements IView { this.controller=controller; } - - public void applyAndRender(NetworkEvent event) { + public void render() { Platform.runLater(() -> { - event.apply(miniModel); - if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { - primaryStage.setScene(totemScene); - controllerTotem.render(); - } else if (controller.miniModel.currentState.getGameStage() == GameStages.ENDED) { - boolean sceneChange = primaryStage.getScene() != leaderboardScene; - primaryStage.setScene(leaderboardScene); - if (sceneChange) { - primaryStage.setMaximized(false); - Platform.runLater(() -> primaryStage.setMaximized(true)); + synchronized (miniModel) { + if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { + primaryStage.setScene(totemScene); + controllerTotem.render(); + } else if (controller.miniModel.currentState.getGameStage() == ENDED) { + primaryStage.setScene(leaderboardScene); + controllerLeaderboard.render(); + } else { + double w = primaryStage.getWidth(); + double h = primaryStage.getHeight(); + primaryStage.setScene(mainScene); + primaryStage.setWidth(w); + primaryStage.setHeight(h); + primaryStage.setMinHeight(h); + primaryStage.setMinWidth(w); + primaryStage.setResizable(false); + controllerMain.render(); } - controllerLeaderboard.render(); - } else { - boolean sceneChange = primaryStage.getScene() != mainScene; // ← era un'altra scena? - primaryStage.setScene(mainScene); - if (sceneChange) { - primaryStage.setMaximized(false); - Platform.runLater(() -> primaryStage.setMaximized(true)); - } - controllerMain.render(event); } }); - } - public void render() { - if (!Platform.isFxApplicationThread()) { - Platform.runLater(this::render); - return; - } - if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { - primaryStage.setScene(totemScene); - controllerTotem.render(); - } else if (controller.miniModel.currentState.getGameStage() == ENDED){ - primaryStage.setScene(leaderboardScene); - controllerLeaderboard.render(); - }else { - primaryStage.setScene(mainScene); - controllerMain.render(); - } } @Override public void showMessage(String message) { @@ -156,7 +132,12 @@ public class GUI extends Application implements IView { @Override public void showError(String message) { - + Platform.runLater(() -> { + synchronized (miniModel) { + controllerMain.isError = true; + controllerMain.render(); + } + }); } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java index 62d3f4a..e49a6c9 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LeaderboardFXMLController.java @@ -6,6 +6,7 @@ import javafx.animation.ScaleTransition; import it.polimi.ingsw.gc14.Model.PlayableCard; import javafx.event.Event; import javafx.fxml.FXML; +import javafx.scene.Scene; import javafx.scene.control.ScrollPane; import javafx.stage.Popup; import javafx.geometry.Insets; @@ -23,6 +24,7 @@ import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Stop; import javafx.scene.paint.CycleMethod; import javafx.scene.text.Font; +import javafx.stage.Stage; import javafx.stage.Window; import javafx.util.Duration; @@ -42,6 +44,8 @@ public class LeaderboardFXMLController { // Cache condivisa con MainFXMLController private static final Map imageCache = new HashMap<>(); + private Scene loginScene; + private Stage primaryStage; private Image loadImage(String path) { return imageCache.computeIfAbsent(path, @@ -49,8 +53,10 @@ public class LeaderboardFXMLController { } - public void setController(ClientController controller) { + public void setController(ClientController controller, Stage primaryStage, Scene loginScene) { this.controller = controller; + this.loginScene=loginScene; + this.primaryStage=primaryStage; } @@ -356,6 +362,6 @@ public class LeaderboardFXMLController { // ==== ACTIONS ==== @FXML private void onNewGame() { - //controller.requestNewGame(); + primaryStage.setScene(loginScene); } } diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java index 59ca329..3c6efce 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java @@ -7,9 +7,8 @@ import it.polimi.ingsw.gc14.Model.Cards.TribeCard; import it.polimi.ingsw.gc14.Model.Orders.OrderPlayer; import it.polimi.ingsw.gc14.Network.EventType; import it.polimi.ingsw.gc14.Network.NetworkEvent; -import javafx.animation.AnimationTimer; -import javafx.animation.PauseTransition; import javafx.animation.ScaleTransition; +import javafx.animation.TranslateTransition; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -18,8 +17,11 @@ import javafx.fxml.FXML; import javafx.geometry.Bounds; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.geometry.Rectangle2D; import javafx.scene.Cursor; import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.effect.ColorAdjust; @@ -31,7 +33,7 @@ import javafx.scene.paint.Color; import javafx.scene.shape.*; import javafx.scene.text.Font; import javafx.stage.Popup; -import javafx.stage.Stage; +import javafx.stage.Screen; import javafx.stage.Window; import javafx.util.Duration; @@ -39,22 +41,24 @@ import java.util.*; public class MainFXMLController { + @FXML private ScrollPane playerSide; @FXML private HBox mainHBox; + @FXML private ImageView backgroundImage; @FXML private HBox board; @FXML private HBox upperList; @FXML private HBox lowerList; @FXML private HBox myHand; - @FXML private VBox sidePanel; - @FXML private HBox info; - @FXML private Label era; - @FXML private Label round; - @FXML private Label player; + @FXML private Button skipBtn; + @FXML private Button detailsBtn; + @FXML private Label infoText; private Popup popup; private HBox popupCards; private ClientController controller; + public boolean isError; + // ==== IMAGE CACHE ==== private static final Map imageCache = new HashMap<>(); @@ -63,43 +67,41 @@ public class MainFXMLController { p -> new Image(getClass().getResourceAsStream(p))); } - public void setController(ClientController controller) { this.controller = controller; } - @FXML public void initialize() { Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); + + popup = new Popup(); mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> { if (newScene != null) { - newScene.getRoot().applyCss(); newScene.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> { if (popup.isShowing()) popup.hide(); }); + newScene.getRoot().applyCss(); + newScene.windowProperty().addListener((o2, ow, nw) -> { + if (nw != null) { + nw.focusedProperty().addListener((o3, wf, nf) -> { + if (!nf) popup.hide(); + }); + } + }); } - }); - mainHBox.layoutBoundsProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue obs, Bounds ov, Bounds nv) { - if (nv.getWidth() > 0 && nv.getHeight() > 0 && controller != null) { - mainHBox.layoutBoundsProperty().removeListener(this); - render(); - } + else { + popup.hide(); } }); initPopup(); renderBackground(); + isError=false; } // ==== RENDER ==== public void render() { - if (mainHBox.getWidth() == 0 || mainHBox.getHeight() == 0) { - Platform.runLater(() -> render()); - return; - } renderUpper(); renderBoard(); renderLower(); @@ -107,37 +109,15 @@ public class MainFXMLController { renderSidePanel(); } - public void render(NetworkEvent event) { - if (mainHBox.getWidth() == 0 || mainHBox.getHeight() == 0) { - Platform.runLater(() -> render(event)); - return; - } - if (event.getEventType() == EventType.SLOT_CHOICE) { - renderBoard(); - renderSidePanel(); - } else { - renderUpper(); - renderBoard(); - renderLower(); - renderSidePanel(); - if (Objects.equals(event.getUsername(), controller.myUsername) - || event.getEventType() == EventType.NEXT_ROUND) { - renderMyHand(); - } - } - } - // ==== EFFECTS ==== private void addClip(ImageView img) { Rectangle clip = new Rectangle(); clip.setArcWidth(20); clip.setArcHeight(20); - clip.heightProperty().bind(img.fitHeightProperty()); - clip.widthProperty().bind(img.fitHeightProperty().multiply( - img.getImage().getWidth() / img.getImage().getHeight() - )); img.setClip(clip); + clip.heightProperty().bind(img.layoutBoundsProperty().map(b -> b.getHeight())); + clip.widthProperty().bind(img.layoutBoundsProperty().map(b -> b.getWidth())); } private void addHoverZoom(Node node) { @@ -176,7 +156,7 @@ public class MainFXMLController { // ==== ELEMENTS ==== private StackPane createOrder(String num) { ImageView img = new ImageView(loadImage("/GUIImages/Orders/order-" + num + ".png")); - img.fitHeightProperty().bind(board.heightProperty().add(-15)); + img.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); img.setPreserveRatio(true); addClip(img); return new StackPane(img); @@ -185,7 +165,7 @@ public class MainFXMLController { private StackPane createSlot(Slot slot, boolean withZoom, boolean withShadow) { ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png")); img.setPreserveRatio(true); - img.fitHeightProperty().bind(board.heightProperty().add(-15)); + img.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); // TODO perchè è tutto moltiplicato per una costante ma in board facciamo -15? addClip(img); StackPane wrapper = new StackPane(img); @@ -195,10 +175,7 @@ public class MainFXMLController { totem.fitHeightProperty().bind(img.fitHeightProperty().multiply(0.332)); totem.setPreserveRatio(true); StackPane.setAlignment(totem, Pos.TOP_LEFT); - StackPane.setMargin(totem, new Insets(0, 0, 0, 0.224 * img.getFitHeight())); - img.fitHeightProperty().addListener((obs, ov, nv) -> { - StackPane.setMargin(totem, new Insets(0, 0, 0, 0.224 * nv.doubleValue())); - }); + StackPane.setMargin(totem, new Insets(0, 0, 0, 0.224 * img.getFitHeight())); // TODO perchè margine sx incrementa con altezza e non larghezza? wrapper.getChildren().add(totem); } @@ -210,7 +187,7 @@ public class MainFXMLController { private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow, Region parent) { ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png")); img.setPreserveRatio(true); - img.fitHeightProperty().bind(parent.heightProperty().multiply(0.85)); + img.fitHeightProperty().bind(parent.heightProperty().multiply(0.90)); addClip(img); StackPane wrapper = new StackPane(img); if (withShadow) addShadow(wrapper); @@ -218,54 +195,6 @@ public class MainFXMLController { return wrapper; } - private void renderIcons(HBox iconsRow1, HBox iconsRow2, Player player) { - String[][] iconTypes = { - {"Artist", "artists"}, - {"Gatherer", "gatherers"}, - {"Inventor", "inventors"}, - {"Builder", "builders"}, - {"Shaman", "shamans"}, - {"Hunter", "hunters"} - }; - - for (int i = 0; i < iconTypes.length; i++) { - String iconName = iconTypes[i][0]; - String fieldName = iconTypes[i][1]; - - ImageView icon = new ImageView(); - icon.setFitWidth(28); - icon.setFitHeight(28); - icon.setPreserveRatio(true); - icon.setImage(loadImage("/GUIImages/Icons/" + iconName + ".png")); - - ArrayList cards = getPlayerCards(player.getUserName(), fieldName); - if (cards.isEmpty()) { - ColorAdjust grayscale = new ColorAdjust(); - icon.setEffect(grayscale); - icon.setOpacity(0.3); - } else { - icon.setOnMouseClicked(e -> openPopup(new ArrayList<>(cards))); - addHoverZoom(icon); - } - - if (i < 3) iconsRow1.getChildren().add(icon); - else iconsRow2.getChildren().add(icon); - } - } - - private ArrayList getPlayerCards(String username, String type) { - Player p = controller.miniModel.players.get(username); - return switch (type) { - case "artists" -> new ArrayList<>(p.artists); - case "gatherers" -> new ArrayList<>(p.gatherers); - case "inventors" -> new ArrayList<>(p.inventors); - case "builders" -> new ArrayList<>(p.builders); - case "shamans" -> new ArrayList<>(p.shamans); - case "hunters" -> new ArrayList<>(p.hunters); - case "building" -> new ArrayList<>(p.buildingCards); - default -> new ArrayList<>(); - }; - } // ==== GROUPS ==== @@ -331,9 +260,9 @@ public class MainFXMLController { } } - private void drawMyHandList(ArrayList cardList, HBox parent) { + private void drawMyHandList(ArrayList cardList) { if (!cardList.isEmpty()) { - StackPane img = createCard(cardList.getLast(), true, true, parent); + StackPane img = createCard(cardList.getLast(), true, true, myHand); Label label = new Label(String.valueOf(cardList.size())); label.setTranslateY(-55); label.setTranslateX(10); @@ -341,23 +270,30 @@ public class MainFXMLController { StackPane.setAlignment(label, Pos.TOP_RIGHT); img.getChildren().add(label); img.setOnMouseClicked(e -> openPopup(new ArrayList<>(cardList))); - parent.getChildren().add(img); + myHand.getChildren().add(img); } else { Region placeholder = new Region(); - placeholder.prefHeightProperty().bind(parent.heightProperty().multiply(0.85)); + placeholder.prefHeightProperty().bind(myHand.heightProperty().multiply(0.90)); placeholder.prefWidthProperty().bind(placeholder.prefHeightProperty().multiply(0.675)); placeholder.setStyle("-fx-background-color: transparent;"); - parent.getChildren().add(placeholder); + myHand.getChildren().add(placeholder); } } private void renderPlayer(Player player,VBox target) { VBox card = new VBox(3); - VBox.setMargin(card, new Insets(15,15,15,15)); + VBox.setMargin(card, new Insets(8,15,8,15)); card.getStyleClass().add("player-card"); - card.setPadding(new Insets(8)); - addHoverZoom(card); - addShadow(card); + card.setPadding(new Insets(4)); + + if(player.getUserName().equals(controller.miniModel.currentState.getCurrentPlayer().getUserName())) { + ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), card); + scaleUp.setToX(1.1); + scaleUp.setToY(1.1); + scaleUp.play(); + } + + // Riga 1: totem + nome HBox headerRow = new HBox(8); @@ -369,6 +305,17 @@ public class MainFXMLController { usernameLabel.getStyleClass().add("label-medium"); if (player.getUserName().equals(controller.myUsername)) { usernameLabel.setStyle("-fx-text-fill: #9d0208"); + + if(isError) { + TranslateTransition tt = new TranslateTransition(Duration.millis(50), card); + tt.setFromX(0); + tt.setByX(10); + tt.setCycleCount(6); + tt.setAutoReverse(true); + tt.play(); + + isError=false; + } } headerRow.getChildren().addAll(totem, usernameLabel); @@ -425,6 +372,55 @@ public class MainFXMLController { target.getChildren().add(card); } + private void renderIcons(HBox iconsRow1, HBox iconsRow2, Player player) { + String[][] iconTypes = { + {"Artist", "artists"}, + {"Gatherer", "gatherers"}, + {"Inventor", "inventors"}, + {"Builder", "builders"}, + {"Shaman", "shamans"}, + {"Hunter", "hunters"} + }; + + for (int i = 0; i < iconTypes.length; i++) { + String iconName = iconTypes[i][0]; + String fieldName = iconTypes[i][1]; + + ImageView icon = new ImageView(); + icon.setFitWidth(28); + icon.setFitHeight(28); + icon.setPreserveRatio(true); + icon.setImage(loadImage("/GUIImages/Icons/" + iconName + ".png")); + + ArrayList cards = getPlayerCards(player.getUserName(), fieldName); + if (cards.isEmpty()) { + ColorAdjust grayscale = new ColorAdjust(); + icon.setEffect(grayscale); + icon.setOpacity(0.3); + } else { + icon.setOnMouseClicked(e -> openPopup(new ArrayList<>(cards))); + addHoverZoom(icon); + } + + if (i < 3) iconsRow1.getChildren().add(icon); + else iconsRow2.getChildren().add(icon); + } + } + + private ArrayList getPlayerCards(String username, String type) { + Player p = controller.miniModel.players.get(username); + return switch (type) { + case "artists" -> new ArrayList<>(p.artists); + case "gatherers" -> new ArrayList<>(p.gatherers); + case "inventors" -> new ArrayList<>(p.inventors); + case "builders" -> new ArrayList<>(p.builders); + case "shamans" -> new ArrayList<>(p.shamans); + case "hunters" -> new ArrayList<>(p.hunters); + case "building" -> new ArrayList<>(p.buildingCards); + default -> new ArrayList<>(); + }; + } + // ==== ABSOLUTES ==== private void renderBackground() { @@ -458,7 +454,7 @@ public class MainFXMLController { default -> "/GUIImages/Backs/back-001.png"; }; ImageView back = new ImageView(loadImage(path)); - back.fitHeightProperty().bind(board.heightProperty().add(-15)); + back.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); back.setPreserveRatio(true); addClip(back); addShadow(back); @@ -476,7 +472,6 @@ public class MainFXMLController { 4, new double[]{0.142, 0.316, 0.503, 0.690}, 5, new double[]{0.066, 0.251, 0.433, 0.617, 0.802} ); - double[] positions = slotPositions.get(numPlayers); if (positions == null) return; @@ -523,17 +518,6 @@ public class MainFXMLController { card.getChildren().add(overlay); board.getChildren().add(card); } - private Color totemColor(Totems totem) { - return switch (totem) { - case ORANGE -> Color.rgb(223, 76, 17); - case BLUE -> Color.rgb(42, 155, 179); - case PURPLE -> Color.rgb(65, 20, 42); - case YELLOW -> Color.rgb(248, 201, 57); - case WHITE -> Color.rgb(232, 232, 231); - // aggiungi i tuoi valori reali - default -> Color.GRAY; - }; - } private void renderSlotMap() { int i = 0; @@ -553,61 +537,33 @@ public class MainFXMLController { myHand.setAlignment(Pos.CENTER); Player me = controller.miniModel.players.get(controller.myUsername); - drawMyHandList(me.artists,myHand); - drawMyHandList(me.gatherers,myHand); - drawMyHandList(me.inventors,myHand); - drawMyHandList(me.builders,myHand); - drawMyHandList(me.shamans,myHand); - drawMyHandList(me.hunters,myHand); - drawMyHandList(me.buildingCards,myHand); + drawMyHandList(me.artists); + drawMyHandList(me.gatherers); + drawMyHandList(me.inventors); + drawMyHandList(me.builders); + drawMyHandList(me.shamans); + drawMyHandList(me.hunters); + drawMyHandList(me.buildingCards); } private void renderSidePanel() { - sidePanel.getChildren().clear(); - sidePanel.setSpacing(6); - - era.setText(Integer.toString(controller.miniModel.currentState.getEra())); - round.setText(Integer.toString(controller.miniModel.currentState.getRound())); - player.setText(controller.miniModel.currentState.getCurrentPlayer().getUserName()); - VBox.setMargin(info, new Insets(5, 5, 5, 5)); - sidePanel.getChildren().add(info); - - HBox buttonRow = new HBox(8); - buttonRow.setAlignment(Pos.CENTER); - VBox.setMargin(buttonRow, new Insets(0, 5, 5, 5)); - - javafx.scene.control.Button skipBtn = new javafx.scene.control.Button("Skip Turn"); - skipBtn.getStyleClass().add("action-button"); + infoText.setText("Round: "+Integer.toString(controller.miniModel.currentState.getRound()) + " • " + controller.miniModel.currentState.getGameStage().toString()); skipBtn.setOnAction(e -> controller.skipTurn(controller.myUsername)); - addHoverZoom(skipBtn); - - javafx.scene.control.Button detailsBtn = new javafx.scene.control.Button("Ending Details"); - detailsBtn.getStyleClass().add("action-button"); detailsBtn.setOnAction(e -> openDetailsPopup()); + + addHoverZoom(skipBtn); addHoverZoom(detailsBtn); - buttonRow.getChildren().addAll(skipBtn, detailsBtn); - sidePanel.getChildren().add(buttonRow); - - // ← VBox separato solo per i player - VBox playerList = new VBox(6); + VBox playerList = new VBox(); playerList.setFillWidth(true); for (Player p : controller.miniModel.players.values()) { - renderPlayer(p, playerList); // ← passa playerList invece di sidePanel + renderPlayer(p, playerList); } - - ScrollPane scrollPane = new ScrollPane(playerList); - scrollPane.setFitToWidth(true); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); - scrollPane.setStyle("-fx-background: transparent; -fx-background-color: transparent;"); - VBox.setVgrow(scrollPane, Priority.ALWAYS); - - sidePanel.getChildren().add(scrollPane); + playerSide.setContent(playerList); } // ==== POPUP ==== - private void initPopup() { + public void initPopup() { popupCards = new HBox(10); popupCards.setAlignment(Pos.CENTER); popupCards.setPadding(new Insets(10)); @@ -619,10 +575,8 @@ public class MainFXMLController { "-fx-background-radius: 10;" ); - popup = new Popup(); popup.getContent().add(popupCards); - popup.setAutoHide(false); // gestito manualmente per permettere click sulle carte - + popup.setAutoHide(false); popup.addEventHandler(Event.ANY, e -> { if (popup.getScene() != null) { popup.getScene().setFill(Color.TRANSPARENT); @@ -676,6 +630,7 @@ public class MainFXMLController { } showPopup(); } + private void openDetailsPopup() { popupCards.getChildren().clear(); ImageView img = new ImageView(loadImage("/GUIImages/Backs/back-118.png")); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/IView.java b/src/main/java/it/polimi/ingsw/gc14/View/IView.java index f10b639..dc0aaa4 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/IView.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/IView.java @@ -7,7 +7,6 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent; public interface IView { public void setModel(MiniModel miniModel); public void render(); - public void applyAndRender(NetworkEvent event); public void showMessage(String message); public void showError(String message); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java index c79faa7..6b318fa 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java @@ -59,10 +59,6 @@ public class TUI implements IView { this.model = model; this.username = ""; } - public void applyAndRender(NetworkEvent event) { - event.apply(model); - render(); - } /** * Sets the username of the local player. diff --git a/src/main/resources/GUIScene/login.fxml b/src/main/resources/GUIScene/login.fxml index ba313ff..b350965 100644 --- a/src/main/resources/GUIScene/login.fxml +++ b/src/main/resources/GUIScene/login.fxml @@ -6,7 +6,6 @@ diff --git a/src/main/resources/GUIScene/main.fxml b/src/main/resources/GUIScene/main.fxml index ebae488..324e2ef 100644 --- a/src/main/resources/GUIScene/main.fxml +++ b/src/main/resources/GUIScene/main.fxml @@ -4,15 +4,16 @@ + + - + - + @@ -48,8 +49,7 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + +