Merge pull request #120

GUI-2.0
This commit is contained in:
rubenpirreram
2026-05-26 17:56:49 +02:00
committed by GitHub
20 changed files with 313 additions and 309 deletions
@@ -8,7 +8,6 @@ import javafx.stage.Stage;
public class ClientLauncherGUI { public class ClientLauncherGUI {
public static void main(String[] args) { public static void main(String[] args) {
System.setProperty("glass.win.uiScale", "1.0");
Application.launch(GUIApp.class, args); Application.launch(GUIApp.class, args);
} }
@@ -1,5 +1,6 @@
package it.polimi.ingsw.gc14; package it.polimi.ingsw.gc14;
import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient; import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient;
import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient; import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient;
@@ -38,6 +39,7 @@ public class ClientLauncherTUI {
*/ */
public void main() throws InterruptedException { public void main() throws InterruptedException {
view = new TUI(null); view = new TUI(null);
admissibleChar.add("0");
admissibleChar.add("1"); admissibleChar.add("1");
admissibleChar.add("2"); admissibleChar.add("2");
admissibleChar.add("3"); admissibleChar.add("3");
@@ -57,6 +59,7 @@ public class ClientLauncherTUI {
System.out.println("Insert username: "); System.out.println("Insert username: ");
String username = scanner.next(); String username = scanner.next();
view.setUsername(username); view.setUsername(username);
controller.setMyUsername(username);
System.out.println("Insert preferred number of players: "); System.out.println("Insert preferred number of players: ");
int proposedNumPlayers = scanner.nextInt(); int proposedNumPlayers = scanner.nextInt();
System.out.println("Select RMI[0] o TCP[1]: "); System.out.println("Select RMI[0] o TCP[1]: ");
@@ -137,7 +140,16 @@ public class ClientLauncherTUI {
if(admissibleChar.contains(action)) if(admissibleChar.contains(action))
{ {
if (!action.equals("6") && !action.equals("A") && !action.equals("B") && !action.equals("C")&&!action.equals("a") && !action.equals("b") && !action.equals("c")) { if(action.equals("0"))
{
System.out.println("Are you sure? Y/N");
String c= scanner.next();
if(!c.equals("Y") && !c.equals("y"))
{
view.render();
return;
}
}else if (!action.equals("6") && !action.equals("A") && !action.equals("B") && !action.equals("C")&&!action.equals("a") && !action.equals("b") && !action.equals("c")) {
try { try {
System.out.println("Insert the required position:"); System.out.println("Insert the required position:");
pos = scanner.nextInt(); pos = scanner.nextInt();
@@ -147,13 +159,17 @@ public class ClientLauncherTUI {
} }
} }
switch (action) { switch (action) {
case "1" -> controller.slotChoice(username, pos); case "0" -> {
case "2" -> controller.drawUpperTribeCard(username, pos); controller.disconnect();
case "3" -> controller.drawUpperBuildingCard(username, pos); System.exit(0);
case "4" -> controller.drawLowerTribeCard(username, pos); }
case "5" -> controller.drawLowerBuildingCard(username, pos); case "1" -> controller.slotChoice(pos);
case "6" -> controller.skipTurn(username); case "2" -> controller.drawUpperTribeCard(pos);
case "7" -> controller.totemChoice(username,pos); case "3" -> controller.drawUpperBuildingCard(pos);
case "4" -> controller.drawLowerTribeCard(pos);
case "5" -> controller.drawLowerBuildingCard(pos);
case "6" -> controller.skipTurn();
case "7" -> controller.totemChoice(pos);
case "A", "a" -> view.fullRender(); case "A", "a" -> view.fullRender();
case "B", "b" -> view.renderBoard(); case "B", "b" -> view.renderBoard();
case "C", "c" -> view.renderPlayer(); case "C", "c" -> view.renderPlayer();
@@ -83,15 +83,11 @@ public class ClientController {
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
* *
* @param playerUsername the username of the player performing the action.
* @param pos the index of the card to draw. * @param pos the index of the card to draw.
*/ */
public void drawUpperTribeCard(String playerUsername, int pos) { public void drawUpperTribeCard(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.drawUpperTribeCard(myUsername, pos);
view.showError("It's not your turn!");
} else {
client.drawUpperTribeCard(playerUsername, pos);
}
} }
/** /**
@@ -100,15 +96,11 @@ public class ClientController {
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
* *
* @param playerUsername the username of the player performing the action.
* @param pos the index of the card to draw. * @param pos the index of the card to draw.
*/ */
public void drawLowerTribeCard(String playerUsername, int pos) { public void drawLowerTribeCard(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.drawLowerTribeCard(myUsername, pos);
view.showError("It's not your turn!");
} else {
client.drawLowerTribeCard(playerUsername, pos);
}
} }
/** /**
@@ -117,15 +109,11 @@ public class ClientController {
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
* *
* @param playerUsername the username of the player performing the action.
* @param pos the index of the card to draw. * @param pos the index of the card to draw.
*/ */
public void drawUpperBuildingCard(String playerUsername, int pos) { public void drawUpperBuildingCard(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.drawUpperBuildingCard(myUsername, pos);
view.showError("It's not your turn!");
} else {
client.drawUpperBuildingCard(playerUsername, pos);
}
} }
/** /**
@@ -134,15 +122,10 @@ public class ClientController {
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
* *
* @param playerUsername the username of the player performing the action.
* @param pos the index of the card to draw. * @param pos the index of the card to draw.
*/ */
public void drawLowerBuildingCard(String playerUsername, int pos) { public void drawLowerBuildingCard(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.drawLowerBuildingCard(myUsername, pos);
view.showError("It's not your turn!");
} else {
client.drawLowerBuildingCard(playerUsername, pos);
}
} }
/** /**
@@ -150,15 +133,9 @@ public class ClientController {
* *
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
*
* @param playerUsername the username of the player performing the action.
*/ */
public void skipTurn(String playerUsername) { public void skipTurn() {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.skipTurn(myUsername);
view.showError("It's not your turn!");
} else {
client.skipTurn(playerUsername);
}
} }
/** /**
@@ -167,15 +144,10 @@ public class ClientController {
* <p>If the specified player is not the current player, an error message * <p>If the specified player is not the current player, an error message
* is shown. Otherwise, the request is forwarded to the network client. * is shown. Otherwise, the request is forwarded to the network client.
* *
* @param playerUsername the username of the player performing the action.
* @param pos the index of the selected slot. * @param pos the index of the selected slot.
*/ */
public void slotChoice(String playerUsername, int pos) { public void slotChoice(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.slotChoice(myUsername, pos);
view.showError("It's not your turn!");
} else {
client.slotChoice(playerUsername, pos);
}
} }
/** /**
@@ -185,14 +157,15 @@ public class ClientController {
* is shown. Otherwise, the selected totem is retrieved from the available * is shown. Otherwise, the selected totem is retrieved from the available
* totems list and the choice is forwarded to the network client. * totems list and the choice is forwarded to the network client.
* *
* @param playerUsername the username of the player making the choice.
* @param pos the index of the selected totem in the available totems list. * @param pos the index of the selected totem in the available totems list.
*/ */
public void totemChoice(String playerUsername, int pos) { public void totemChoice(int pos) {
if (!Objects.equals(playerUsername, miniModel.currentState.getCurrentPlayer().getUserName())) { client.totemChoice(myUsername, String.valueOf(miniModel.availableTotems.get(pos)));
view.showError("It's not your turn!");
} else { }
client.totemChoice(playerUsername, String.valueOf(miniModel.availableTotems.get(pos)));
} public void disconnect()
{
client.notifyDisconnection();
} }
} }
@@ -70,4 +70,7 @@ public interface IClient {
* @param totem the name of the selected totem. * @param totem the name of the selected totem.
*/ */
void totemChoice(String playerUsername, String totem); void totemChoice(String playerUsername, String totem);
//TODO
void notifyDisconnection();
} }
@@ -107,7 +107,7 @@ public class RMIClient implements IClient {
future.get(PING_TIMEOUT_MS, TimeUnit.MILLISECONDS); // mirrors setSoTimeout(5000) future.get(PING_TIMEOUT_MS, TimeUnit.MILLISECONDS); // mirrors setSoTimeout(5000)
} catch (TimeoutException e) { } catch (TimeoutException e) {
future.cancel(true); future.cancel(true);
System.out.println("RMI ping timeout: " + username); //error sending
disconnect(); disconnect();
} catch (Exception e) { } catch (Exception e) {
disconnect(); disconnect();
@@ -124,7 +124,7 @@ public class RMIClient implements IClient {
if (!running) return; if (!running) return;
running = false; running = false;
if (pingSender != null) pingSender.shutdownNow(); if (pingSender != null) pingSender.shutdownNow();
controller.view.showError("Connessione al server persa"); controller.view.showError("Connection with server closed");
} }
@@ -235,5 +235,15 @@ public class RMIClient implements IClient {
} }
} }
public void notifyDisconnection() {
pingSender.shutdownNow();
try{
stub.disconnectPlayer(username);
}
catch (RemoteException e){
System.out.println("Error during remote disconnection");
}
}
} }
@@ -93,4 +93,6 @@ public interface IGameServer extends Remote {
* @throws RemoteException if an RMI communication error occurs. * @throws RemoteException if an RMI communication error occurs.
*/ */
void ping(String username) throws RemoteException; void ping(String username) throws RemoteException;
void disconnectPlayer(String username) throws RemoteException;
} }
@@ -89,7 +89,7 @@ public class RMIHeartbeat {
* the associated RMI callback is removed, and a disconnection event is * the associated RMI callback is removed, and a disconnection event is
* added to the action queue for server-side processing. * added to the action queue for server-side processing.
*/ */
private void disconnect() { public void disconnect() {
if (!running) return; if (!running) return;
running = false; running = false;
watchdog.shutdownNow(); watchdog.shutdownNow();
@@ -47,16 +47,6 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
BlockingQueue<NetworkEvent> actionQueue; BlockingQueue<NetworkEvent> actionQueue;
private LimitedMap<String, Boolean> playerList; private LimitedMap<String, Boolean> playerList;
private boolean serverCrashed;
/**
* Sets whether the server is recovering from a previous crash.
*
* @param serverCrashed {@code true} if the server is in crash-recovery mode,
*/
public void setServerCrashed(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
}
/** /**
* Constructs an RMI server with the required game and network components. * Constructs an RMI server with the required game and network components.
@@ -96,30 +86,25 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
if (preferredInt < 2 || preferredInt > 5) return false; if (preferredInt < 2 || preferredInt > 5) return false;
synchronized (controller) { synchronized (controller) {
if(serverCrashed)
{ if (playerList.isEmpty() && controller.getModel()==null) {
if(controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))&& !playerList.containsKey(username)) { controller.setModel(new Game(preferredInt));
clients.put(username, callback); playerList.setLimit(preferredInt);
playerList.put(username, true); System.out.println("Game Created With :"+preferredInt+" Players");
startWatchdog(username);
System.out.println("(After crash)Reconnected player: " + username);
return true;
}
} }
else if (controller.addPlayer(username)) {
{ clients.put(username, callback);
if (playerList.isEmpty()) { playerList.put(username, true);
controller.setModel(new Game(preferredInt)); startWatchdog(username);
playerList.setLimit(preferredInt); System.out.println("Accepted player: " + username);
System.out.println("Game Created With :"+preferredInt+" Players"); return true;
} }
if (controller.addPlayer(username)) { if(controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))&& !playerList.containsKey(username)) {
clients.put(username, callback); clients.put(username, callback);
playerList.put(username, true); playerList.put(username, true);
startWatchdog(username); startWatchdog(username);
System.out.println("Accepted player: " + username); System.out.println("(After crash)Reconnected player: " + username);
return true; return true;
}
} }
if (playerList.containsKey(username) && !playerList.get(username)) { if (playerList.containsKey(username) && !playerList.get(username)) {
playerList.put(username, true); playerList.put(username, true);
@@ -279,13 +264,10 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* on the specified port, and registers this server instance under the * on the specified port, and registers this server instance under the
* {@code RMIGameServer} name. * {@code RMIGameServer} name.
* *
* @param serverCrashed {@code true} if the server is being restarted after a crash,
* {@code false} otherwise.
* @return {@code true} if the server starts successfully, * @return {@code true} if the server starts successfully,
* {@code false} otherwise. * {@code false} otherwise.
*/ */
public boolean start(boolean serverCrashed) { public boolean start() {
this.serverCrashed = serverCrashed;
try { try {
System.setProperty("java.rmi.server.hostname", host); System.setProperty("java.rmi.server.hostname", host);
registry = LocateRegistry.createRegistry(nPort); registry = LocateRegistry.createRegistry(nPort);
@@ -332,6 +314,10 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
watchdogs.put(username, wd); watchdogs.put(username, wd);
wd.start(); wd.start();
} }
public void disconnectPlayer(String username) {
RMIHeartbeat wd = watchdogs.get(username);
wd.disconnect();
}
@@ -107,8 +107,12 @@ public class TCPClient implements IClient {
ScheduledExecutorService sender = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService sender = Executors.newSingleThreadScheduledExecutor();
sender.scheduleAtFixedRate(() -> { sender.scheduleAtFixedRate(() -> {
try { try {
heartbeatOut.write(PING); synchronized (heartbeatOut)
heartbeatOut.flush(); {
heartbeatOut.write(PING);
heartbeatOut.flush();
}
} catch (IOException e) { } catch (IOException e) {
sender.shutdownNow(); sender.shutdownNow();
disconnect(); disconnect();
@@ -263,4 +267,17 @@ public class TCPClient implements IClient {
public void totemChoice(String playerUsername,String totems) { public void totemChoice(String playerUsername,String totems) {
doEvent(new TotemChoice(playerUsername,totems)); doEvent(new TotemChoice(playerUsername,totems));
} }
public void notifyDisconnection()
{
synchronized (heartbeatOut)
{
try {
heartbeatOut.write(-1);
} catch (IOException e) {
disconnect();
}
}
disconnect();
}
} }
@@ -94,10 +94,9 @@ public class ClientHandler implements Runnable {
} }
} }
} catch (IOException e) { } catch (IOException e) {
clientHandlers.remove(this); System.err.println("Error in incoming connection/disconnection");
e.printStackTrace();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new RuntimeException(e); System.err.println("Class not found");
} }
} }
@@ -94,7 +94,13 @@ public class HeartbeatHandler implements Runnable {
try { try {
while (running) { while (running) {
int b = in.read(); // blocca finché non arriva un byte int b = in.read(); // blocca finché non arriva un byte
if (b == -1) { disconnect(); break; } // stream chiusa if (b == -1) {
synchronized (this)
{
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);
@@ -127,7 +133,7 @@ public class HeartbeatHandler implements Runnable {
* <p>The handler is stopped, the watchdog task is terminated, the main * <p>The handler is stopped, the watchdog task is terminated, the main
* {@link ClientHandler} is disconnected, and the heartbeat socket is closed. * {@link ClientHandler} is disconnected, and the heartbeat socket is closed.
*/ */
private void disconnect() { private synchronized void disconnect() {
running = false; running = false;
watchdog.shutdownNow(); watchdog.shutdownNow();
mainHandler.disconnect(); // disconnette anche il socket principale mainHandler.disconnect(); // disconnette anche il socket principale
@@ -73,20 +73,6 @@ public class TCPServer {
*/ */
List<ClientHandler> clientHandlers; List<ClientHandler> clientHandlers;
/**
* Flag indicating whether the server is recovering from a previous crash.
*/
boolean serverCrashed;
/**
* Sets whether the server is recovering from a previous crash.
*
* @param serverCrashed {@code true} if the server is in crash-recovery mode,
* {@code false} otherwise.
*/
public void setServerCrashed(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
}
/** /**
* Temporary map associating each username with the corresponding * Temporary map associating each username with the corresponding
@@ -129,12 +115,8 @@ public class TCPServer {
* the connection is handled either as a new player joining the game * the connection is handled either as a new player joining the game
* or as a reconnection attempt. * or as a reconnection attempt.
* *
* @param serverCrashed {@code true} if the server is being restarted after a crash,
* {@code false} otherwise.
*/ */
public void start(boolean serverCrashed) { public void start() {
this.serverCrashed = serverCrashed;
try { try {
socketTCP = new ServerSocket(port); socketTCP = new ServerSocket(port);
heartbeatSocketTCP = new ServerSocket(heartbeatPort); heartbeatSocketTCP = new ServerSocket(heartbeatPort);
@@ -180,70 +162,64 @@ public class TCPServer {
synchronized (controller) { synchronized (controller) {
String username = eventAddPlayer.getUsername(); String username = eventAddPlayer.getUsername();
//reconnect players after a server crash //reconnect players after a server crash
if (serverCrashed) { if (playerList.isEmpty()&& controller.getModel()==null) {
if (controller.getModel().getPlayers().stream() Game model = new Game(eventAddPlayer.getProposedNPlayer());
.anyMatch(p -> p.getUserName().equals(username)) controller.setModel(model);
&& !playerList.containsKey(username)) { playerList.setLimit(eventAddPlayer.getProposedNPlayer());
playerList.put(username, true); System.out.println("Game Created With :"+eventAddPlayer.getProposedNPlayer()+" Players");
System.out.println("(After crash)Reconnected player: " + username); }
ClientHandler handler = new ClientHandler( if (controller.addPlayer(username)) {
username, playerList.put(username, true);
clientSocket, System.out.println("Accepted player: " + username);
clientSend,
clientReceive,
clientHandlers,
playerList,
actionQueue
);
clientSocket.getOutputStream().write(1); ClientHandler handler = new ClientHandler(
pendingHeartbeat.put(username, handler); username,
clientSocket,
clientSend,
clientReceive,
clientHandlers,
playerList,
actionQueue
);
Thread thread = new Thread(handler); clientSocket.getOutputStream().write(1);
thread.start(); pendingHeartbeat.put(username, handler);
clientHandlers.add(handler); Thread thread = new Thread(handler);
connectedPlayers++; thread.start();
return;
} clientHandlers.add(handler);
connectedPlayers++;
continue;
} }
//manages a new player adding if (controller.getModel().getPlayers().stream()
else { .anyMatch(p -> p.getUserName().equals(username))
if (playerList.isEmpty()) { && !playerList.containsKey(username)) {
Game model = new Game(eventAddPlayer.getProposedNPlayer()); playerList.put(username, true);
controller.setModel(model); System.out.println("(After crash)Reconnected player: " + username);
playerList.setLimit(eventAddPlayer.getProposedNPlayer());
System.out.println("Game Created With :"+eventAddPlayer.getProposedNPlayer()+" Players");
}
if (controller.addPlayer(username)) { ClientHandler handler = new ClientHandler(
playerList.put(username, true); username,
System.out.println("Accepted player: " + username); clientSocket,
clientSend,
clientReceive,
clientHandlers,
playerList,
actionQueue
);
ClientHandler handler = new ClientHandler( clientSocket.getOutputStream().write(1);
username, pendingHeartbeat.put(username, handler);
clientSocket,
clientSend,
clientReceive,
clientHandlers,
playerList,
actionQueue
);
clientSocket.getOutputStream().write(1); Thread thread = new Thread(handler);
pendingHeartbeat.put(username, handler); thread.start();
Thread thread = new Thread(handler); clientHandlers.add(handler);
thread.start(); connectedPlayers++;
continue;
clientHandlers.add(handler);
connectedPlayers++;
return;
}
} }
//reconnect a previously disconnected player //reconnect a previously disconnected player
if (playerList.containsKey(username) if (playerList.containsKey(username)
@@ -288,8 +264,6 @@ public class TCPServer {
System.out.println("Player could not be added. Connection terminated."); System.out.println("Player could not be added. Connection terminated.");
} }
} }
} catch (IOException | ClassNotFoundException e) { } catch (IOException | ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -186,8 +186,6 @@ public class ServerLauncher {
if(!entry.getValue()) if(!entry.getValue())
playerList.remove(entry.getKey()); playerList.remove(entry.getKey());
} }
serverRMI.setServerCrashed(false);
serverTCP.setServerCrashed(false);
} }
//notify the event //notify the event
else { else {
@@ -195,6 +193,10 @@ public class ServerLauncher {
serverTCP.notifyAll(event); serverTCP.notifyAll(event);
} }
} }
else {
serverRMI.notifyAll(event);
serverTCP.notifyAll(event);
}
return !event.getIsError(); return !event.getIsError();
} }
} }
@@ -202,13 +204,15 @@ public class ServerLauncher {
// removes disconneted players when the game is ended // removes disconneted players when the game is ended
if(event.getEventType().equals(EventType.DISCONNECTED_PLAYER)) if(event.getEventType().equals(EventType.DISCONNECTED_PLAYER))
{ {
playerList.remove(event.getUsername()); synchronized (gameController) {
if(playerList.isEmpty()) 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"); gameController.setModel(null);
System.out.println("\n!!! Player list is now empty, ready for a new game init !!!\n");
}
return true;
} }
return true;
} }
return false; return false;
} }
@@ -241,7 +245,6 @@ public class ServerLauncher {
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>(); BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
GameController gameController = new GameController(); GameController gameController = new GameController();
String IP; String IP;
boolean serverCrashed;
try { try {
IP=chooseNetworkInterface(new Scanner(System.in)); IP=chooseNetworkInterface(new Scanner(System.in));
System.out.println(IP); System.out.println(IP);
@@ -262,10 +265,6 @@ public class ServerLauncher {
playerList.put(entry.getKey().getUserName(),false); playerList.put(entry.getKey().getUserName(),false);
} }
} }
serverCrashed = true;
} else {
serverCrashed = false;
} }
playerList.setAction(()->{ playerList.setAction(()->{
new Thread(()->{ new Thread(()->{
@@ -277,8 +276,6 @@ public class ServerLauncher {
} }
serverRMI.notifyAll(miniModel); serverRMI.notifyAll(miniModel);
serverTCP.notifyAll(miniModel); serverTCP.notifyAll(miniModel);
view = new TUI(miniModel);
view.render();
}).start(); }).start();
}); });
new Thread(()-> { new Thread(()-> {
@@ -291,8 +288,8 @@ public class ServerLauncher {
} }
}).start(); }).start();
serverRMI.start(serverCrashed); serverRMI.start();
new Thread(()->{serverTCP.start(serverCrashed);}).start(); new Thread(()->{serverTCP.start();}).start();
System.out.println("Server RMI: "+System.getProperty("java.rmi.server.hostname")); System.out.println("Server RMI: "+System.getProperty("java.rmi.server.hostname"));
} }
@@ -310,10 +307,6 @@ public class ServerLauncher {
while (true) { while (true) {
try{ try{
this.doFirstEvent(); this.doFirstEvent();
// if(view!=null)
// {
// view.fullRender();
// }
} }
catch(InterruptedException e){ catch(InterruptedException e){
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@@ -13,7 +13,9 @@ import javafx.application.Platform;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.util.Duration; import javafx.util.Duration;
@@ -62,23 +64,28 @@ public class GUI extends Application implements IView {
loaderMain = new FXMLLoader(getClass().getResource("/GUIScene/main.fxml")); loaderMain = new FXMLLoader(getClass().getResource("/GUIScene/main.fxml"));
loaderMain.setControllerFactory(clazz -> { mainScene = new Scene(loaderMain.load());
MainFXMLController controllerMain = new MainFXMLController(); controllerMain = loaderMain.getController();
controllerMain.setController(controller); controllerMain.setController(controller);
return controllerMain;
});
loaderLeaderboard = new FXMLLoader(getClass().getResource("/GUIScene/standing.fxml")); loaderLeaderboard = new FXMLLoader(getClass().getResource("/GUIScene/standing.fxml"));
leaderboardScene = new Scene(loaderLeaderboard.load()); leaderboardScene = new Scene(loaderLeaderboard.load());
controllerLeaderboard = loaderLeaderboard.getController(); controllerLeaderboard = loaderLeaderboard.getController();
controllerLeaderboard.setController(controller,primaryStage,loginScene); controllerLeaderboard.setController(controller,primaryStage,loginScene);
mainScene = new Scene(loaderMain.load());
controllerMain = loaderMain.getController();
showLogin();
primaryStage.setScene(loginScene);
primaryStage.setFullScreen(true);
Rectangle2D tmp = Screen.getPrimary().getVisualBounds();
primaryStage.setWidth(tmp.getWidth());
primaryStage.setHeight(tmp.getHeight());
primaryStage.setX(tmp.getMinX());
primaryStage.setY(tmp.getMinY());
primaryStage.setResizable(false);
primaryStage.setTitle("Mesos"); primaryStage.setTitle("Mesos");
primaryStage.setOnCloseRequest(e -> { primaryStage.setOnCloseRequest(e -> {
Platform.exit(); Platform.exit();
@@ -87,10 +94,6 @@ public class GUI extends Application implements IView {
primaryStage.show(); primaryStage.show();
} }
public void showLogin() throws IOException {
primaryStage.setScene(loginScene);
}
@Override @Override
public void setModel(MiniModel miniModel) { public void setModel(MiniModel miniModel) {
@@ -103,24 +106,34 @@ public class GUI extends Application implements IView {
public void render() { public void render() {
Platform.runLater(() -> { Platform.runLater(() -> {
boolean toFull=false;
synchronized (miniModel) { synchronized (miniModel) {
if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) {
primaryStage.setScene(totemScene); if (primaryStage.getScene()!=leaderboardScene) {
toFull=true;
}
controllerTotem.render(); controllerTotem.render();
primaryStage.setScene(totemScene);
} else if (controller.miniModel.currentState.getGameStage() == ENDED) { } else if (controller.miniModel.currentState.getGameStage() == ENDED) {
primaryStage.setScene(leaderboardScene); if (primaryStage.getScene()!=leaderboardScene) {
toFull=true;
}
controllerLeaderboard.render(); controllerLeaderboard.render();
primaryStage.setScene(leaderboardScene);
} else { } else {
double w = primaryStage.getWidth(); if (primaryStage.getScene()!=mainScene) {
double h = primaryStage.getHeight(); toFull=true;
}
//double w = primaryStage.getWidth();
//double h = primaryStage.getHeight();
primaryStage.setScene(mainScene); primaryStage.setScene(mainScene);
primaryStage.setWidth(w);
primaryStage.setHeight(h);
primaryStage.setMinHeight(h);
primaryStage.setMinWidth(w);
primaryStage.setResizable(false);
controllerMain.render(); controllerMain.render();
} }
if (toFull) {
primaryStage.setFullScreen(true);
}
} }
}); });
@@ -136,6 +149,7 @@ public class GUI extends Application implements IView {
synchronized (miniModel) { synchronized (miniModel) {
controllerMain.isError = true; controllerMain.isError = true;
controllerMain.render(); controllerMain.render();
System.out.println("ERRORE PORCODIDODODODOD");
} }
}); });
} }
@@ -362,6 +362,7 @@ public class LeaderboardFXMLController {
// ==== ACTIONS ==== // ==== ACTIONS ====
@FXML @FXML
private void onNewGame() { private void onNewGame() {
controller.disconnect();
primaryStage.setScene(loginScene); primaryStage.setScene(loginScene);
} }
} }
@@ -41,6 +41,7 @@ import java.util.*;
public class MainFXMLController { public class MainFXMLController {
@FXML private GridPane leftGrid;
@FXML private ScrollPane playerSide; @FXML private ScrollPane playerSide;
@FXML private HBox mainHBox; @FXML private HBox mainHBox;
@FXML private ImageView backgroundImage; @FXML private ImageView backgroundImage;
@@ -75,6 +76,7 @@ public class MainFXMLController {
public void initialize() { public void initialize() {
Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14);
popup = new Popup(); popup = new Popup();
mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> { mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) { if (newScene != null) {
@@ -102,11 +104,16 @@ public class MainFXMLController {
// ==== RENDER ==== // ==== RENDER ====
public void render() { public void render() {
renderUpper();
renderBoard(); if(!isError) {
renderLower(); renderUpper();
renderMyHand(); renderBoard();
renderLower();
renderMyHand();
}
renderSidePanel(); renderSidePanel();
} }
@@ -156,7 +163,7 @@ public class MainFXMLController {
// ==== ELEMENTS ==== // ==== ELEMENTS ====
private StackPane createOrder(String num) { private StackPane createOrder(String num) {
ImageView img = new ImageView(loadImage("/GUIImages/Orders/order-" + num + ".png")); ImageView img = new ImageView(loadImage("/GUIImages/Orders/order-" + num + ".png"));
img.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); img.fitHeightProperty().bind(board.sceneProperty().get().heightProperty().subtract(40).divide(4).multiply(0.94));
img.setPreserveRatio(true); img.setPreserveRatio(true);
addClip(img); addClip(img);
return new StackPane(img); return new StackPane(img);
@@ -165,7 +172,7 @@ public class MainFXMLController {
private StackPane createSlot(Slot slot, boolean withZoom, boolean withShadow) { private StackPane createSlot(Slot slot, boolean withZoom, boolean withShadow) {
ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png")); ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png"));
img.setPreserveRatio(true); img.setPreserveRatio(true);
img.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); // TODO perchè è tutto moltiplicato per una costante ma in board facciamo -15? img.fitHeightProperty().bind(board.sceneProperty().get().heightProperty().subtract(40).divide(4).multiply(0.94));
addClip(img); addClip(img);
StackPane wrapper = new StackPane(img); StackPane wrapper = new StackPane(img);
@@ -175,7 +182,7 @@ public class MainFXMLController {
totem.fitHeightProperty().bind(img.fitHeightProperty().multiply(0.332)); totem.fitHeightProperty().bind(img.fitHeightProperty().multiply(0.332));
totem.setPreserveRatio(true); totem.setPreserveRatio(true);
StackPane.setAlignment(totem, Pos.TOP_LEFT); StackPane.setAlignment(totem, Pos.TOP_LEFT);
StackPane.setMargin(totem, new Insets(0, 0, 0, 0.224 * img.getFitHeight())); // TODO perchè margine sx incrementa con altezza e non larghezza? StackPane.setMargin(totem, new Insets(0, 0, 0, 0.224 * img.getFitHeight()));
wrapper.getChildren().add(totem); wrapper.getChildren().add(totem);
} }
@@ -187,7 +194,7 @@ public class MainFXMLController {
private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow, Region parent) { private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow, Region parent) {
ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png")); ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png"));
img.setPreserveRatio(true); img.setPreserveRatio(true);
img.fitHeightProperty().bind(parent.heightProperty().multiply(0.90)); img.fitHeightProperty().bind(parent.getScene().heightProperty().subtract(40).divide(4).multiply(0.90));
addClip(img); addClip(img);
StackPane wrapper = new StackPane(img); StackPane wrapper = new StackPane(img);
if (withShadow) addShadow(wrapper); if (withShadow) addShadow(wrapper);
@@ -207,7 +214,7 @@ public class MainFXMLController {
for (TribeCard card : controller.miniModel.upperListTribeCards) { for (TribeCard card : controller.miniModel.upperListTribeCards) {
final int index = i; final int index = i;
StackPane img = createCard(card, true, true, upperList); StackPane img = createCard(card, true, true, upperList);
img.setOnMouseClicked(e -> controller.drawUpperTribeCard(controller.myUsername, index)); img.setOnMouseClicked(e -> controller.drawUpperTribeCard(index));
upperList.getChildren().add(img); upperList.getChildren().add(img);
i++; i++;
} }
@@ -223,7 +230,7 @@ public class MainFXMLController {
for (TribeCard card : controller.miniModel.lowerListTribeCards) { for (TribeCard card : controller.miniModel.lowerListTribeCards) {
final int index = i; final int index = i;
StackPane img = createCard(card, true, true, lowerList); StackPane img = createCard(card, true, true, lowerList);
img.setOnMouseClicked(e -> controller.drawLowerTribeCard(controller.myUsername, index)); img.setOnMouseClicked(e -> controller.drawLowerTribeCard(index));
lowerList.getChildren().add(img); lowerList.getChildren().add(img);
i++; i++;
} }
@@ -273,7 +280,7 @@ public class MainFXMLController {
myHand.getChildren().add(img); myHand.getChildren().add(img);
} else { } else {
Region placeholder = new Region(); Region placeholder = new Region();
placeholder.prefHeightProperty().bind(myHand.heightProperty().multiply(0.90)); placeholder.prefHeightProperty().bind(myHand.getScene().heightProperty().subtract(40).divide(4).multiply(0.90));
placeholder.prefWidthProperty().bind(placeholder.prefHeightProperty().multiply(0.675)); placeholder.prefWidthProperty().bind(placeholder.prefHeightProperty().multiply(0.675));
placeholder.setStyle("-fx-background-color: transparent;"); placeholder.setStyle("-fx-background-color: transparent;");
myHand.getChildren().add(placeholder); myHand.getChildren().add(placeholder);
@@ -282,7 +289,7 @@ public class MainFXMLController {
private void renderPlayer(Player player,VBox target) { private void renderPlayer(Player player,VBox target) {
VBox card = new VBox(3); VBox card = new VBox(3);
VBox.setMargin(card, new Insets(8,15,8,15)); VBox.setMargin(card, new Insets(15,15,0,15));
card.getStyleClass().add("player-card"); card.getStyleClass().add("player-card");
card.setPadding(new Insets(4)); card.setPadding(new Insets(4));
@@ -291,6 +298,8 @@ public class MainFXMLController {
scaleUp.setToX(1.1); scaleUp.setToX(1.1);
scaleUp.setToY(1.1); scaleUp.setToY(1.1);
scaleUp.play(); scaleUp.play();
card.setStyle("-fx-effect: dropshadow(gaussian, #fff8dc, 15, 0.10, 0, 0)");
} }
@@ -303,8 +312,9 @@ public class MainFXMLController {
totem.setPreserveRatio(true); totem.setPreserveRatio(true);
Label usernameLabel = new Label(player.getUserName()); Label usernameLabel = new Label(player.getUserName());
usernameLabel.getStyleClass().add("label-medium"); usernameLabel.getStyleClass().add("label-medium");
usernameLabel.setStyle("-fx-text-fill: #711423;");
if (player.getUserName().equals(controller.myUsername)) { if (player.getUserName().equals(controller.myUsername)) {
usernameLabel.setStyle("-fx-text-fill: #9d0208"); usernameLabel.setText(usernameLabel.getText() + " (you)");
if(isError) { if(isError) {
TranslateTransition tt = new TranslateTransition(Duration.millis(50), card); TranslateTransition tt = new TranslateTransition(Duration.millis(50), card);
@@ -454,7 +464,7 @@ public class MainFXMLController {
default -> "/GUIImages/Backs/back-001.png"; default -> "/GUIImages/Backs/back-001.png";
}; };
ImageView back = new ImageView(loadImage(path)); ImageView back = new ImageView(loadImage(path));
back.fitHeightProperty().bind(board.heightProperty().multiply(0.94)); back.fitHeightProperty().bind(board.sceneProperty().get().heightProperty().divide(4).multiply(0.94));
back.setPreserveRatio(true); back.setPreserveRatio(true);
addClip(back); addClip(back);
addShadow(back); addShadow(back);
@@ -525,7 +535,7 @@ public class MainFXMLController {
Slot slot = entry.getKey(); Slot slot = entry.getKey();
final int index = i; final int index = i;
StackPane img = createSlot(slot, true, true); StackPane img = createSlot(slot, true, true);
img.setOnMouseClicked(e -> controller.slotChoice(controller.myUsername, index)); img.setOnMouseClicked(e -> controller.slotChoice(index));
board.getChildren().add(img); board.getChildren().add(img);
i++; i++;
} }
@@ -548,7 +558,7 @@ public class MainFXMLController {
private void renderSidePanel() { private void renderSidePanel() {
infoText.setText("Round: "+Integer.toString(controller.miniModel.currentState.getRound()) + "" + controller.miniModel.currentState.getGameStage().toString()); infoText.setText("Round: "+Integer.toString(controller.miniModel.currentState.getRound()) + "" + controller.miniModel.currentState.getGameStage().toString());
skipBtn.setOnAction(e -> controller.skipTurn(controller.myUsername)); skipBtn.setOnAction(e -> controller.skipTurn());
detailsBtn.setOnAction(e -> openDetailsPopup()); detailsBtn.setOnAction(e -> openDetailsPopup());
addHoverZoom(skipBtn); addHoverZoom(skipBtn);
@@ -609,7 +619,7 @@ public class MainFXMLController {
StackPane img = createCardPopup(cardList.get(i), true, false); StackPane img = createCardPopup(cardList.get(i), true, false);
img.setOnMouseClicked(e -> { img.setOnMouseClicked(e -> {
popup.hide(); popup.hide();
controller.drawUpperBuildingCard(controller.myUsername, index); controller.drawUpperBuildingCard(index);
}); });
popupCards.getChildren().add(img); popupCards.getChildren().add(img);
} }
@@ -624,7 +634,7 @@ public class MainFXMLController {
StackPane img = createCardPopup(cardList.get(i), true, false); StackPane img = createCardPopup(cardList.get(i), true, false);
img.setOnMouseClicked(e -> { img.setOnMouseClicked(e -> {
popup.hide(); popup.hide();
controller.drawLowerBuildingCard(controller.myUsername, index); controller.drawLowerBuildingCard(index);
}); });
popupCards.getChildren().add(img); popupCards.getChildren().add(img);
} }
@@ -197,7 +197,7 @@ public class TotemFXMLController {
@FXML @FXML
private void onConfirm() { private void onConfirm() {
if (selectedIndex >= 0) { if (selectedIndex >= 0) {
controller.totemChoice(controller.myUsername, selectedIndex); controller.totemChoice(selectedIndex);
} }
} }
} }
@@ -257,6 +257,7 @@ public class TUI implements IView {
table.addRow(List.of("4-DrawLowerTribe(pos)", "")); table.addRow(List.of("4-DrawLowerTribe(pos)", ""));
table.addRow(List.of("5-DrawLowerBuilding(pos)", "")); table.addRow(List.of("5-DrawLowerBuilding(pos)", ""));
table.addRow(List.of("6-SkipTurn", "")); table.addRow(List.of("6-SkipTurn", ""));
table.addRow(List.of("0-Disconnect", ""));
return table.build(); return table.build();
} }
+67 -67
View File
@@ -13,78 +13,78 @@
fx:controller="it.polimi.ingsw.gc14.View.GUI.MainFXMLController" fx:controller="it.polimi.ingsw.gc14.View.GUI.MainFXMLController"
stylesheets="@styles.css"> stylesheets="@styles.css">
<children> <children>
<!-- VBox sinistra: si espande per riempire tutto lo spazio disponibile --> <!-- VBox sinistra: si espande per riempire tutto lo spazio disponibile -->
<VBox alignment="CENTER" <VBox alignment="CENTER"
fillWidth="false" fillWidth="false"
maxHeight="Infinity" maxHeight="Infinity"
maxWidth="Infinity" maxWidth="Infinity"
HBox.hgrow="ALWAYS"> HBox.hgrow="ALWAYS">
<HBox.margin> <HBox.margin>
<Insets top="5" right="5" bottom="5" left="5" /> <Insets top="5" right="5" bottom="5" left="5" />
</HBox.margin> </HBox.margin>
<children> <children>
<HBox fx:id="upperList" styleClass="card-list" VBox.vgrow="ALWAYS"> <HBox fx:id="upperList" styleClass="card-list" VBox.vgrow="ALWAYS">
<VBox.margin> <VBox.margin>
<Insets top="5" right="5" bottom="5" left="5" /> <Insets top="5" right="5" bottom="5" left="5" />
</VBox.margin> </VBox.margin>
</HBox> </HBox>
<HBox fx:id="board" prefHeight="280" minHeight="280" maxHeight="280" styleClass="card-list" VBox.vgrow="NEVER"> <HBox fx:id="board" styleClass="card-list" VBox.vgrow="NEVER">
<VBox.margin> <VBox.margin>
<Insets top="5" right="5" bottom="5" left="5" /> <Insets top="5" right="5" bottom="5" left="5" />
</VBox.margin> </VBox.margin>
</HBox> </HBox>
<HBox fx:id="lowerList" styleClass="card-list" VBox.vgrow="ALWAYS"> <HBox fx:id="lowerList" styleClass="card-list" VBox.vgrow="ALWAYS">
<VBox.margin> <VBox.margin>
<Insets top="5" right="5" bottom="5" left="5" /> <Insets top="5" right="5" bottom="5" left="5" />
</VBox.margin> </VBox.margin>
</HBox> </HBox>
<HBox fx:id="myHand" styleClass="card-list" VBox.vgrow="ALWAYS"> <HBox fx:id="myHand" styleClass="card-list" VBox.vgrow="ALWAYS">
<VBox.margin> <VBox.margin>
<Insets top="5" right="5" bottom="5" left="5" /> <Insets top="5" right="5" bottom="5" left="5" />
</VBox.margin> </VBox.margin>
</HBox> </HBox>
</children> </children>
</VBox> </VBox>
<!-- VBox destra: dimensione fissa, non si espande --> <!-- VBox destra: dimensione fissa, non si espande -->
<VBox fx:id="sidePanel" <VBox fx:id="sidePanel"
prefWidth="250.0" prefWidth="250.0"
maxWidth="250.0" maxWidth="250.0"
minWidth="250.0" minWidth="250.0"
HBox.hgrow="NEVER" HBox.hgrow="NEVER"
styleClass="side-panel"> styleClass="side-panel">
<HBox.margin> <HBox.margin>
<Insets bottom="10" left="10" right="10" top="10" /> <Insets bottom="10" left="10" right="10" top="10" />
</HBox.margin> </HBox.margin>
<children> <children>
<HBox fx:id="info" prefHeight="80.0" prefWidth="483.0" styleClass="frame" alignment="CENTER"> <HBox fx:id="info" prefHeight="80.0" prefWidth="483.0" styleClass="frame" alignment="CENTER">
<Label fx:id="infoText" styleClass="label-medium" text="VALORE" /> <Label fx:id="infoText" styleClass="label-medium" text="VALORE" />
</HBox> </HBox>
<ScrollPane fx:id="playerSide" fitToWidth="true" <ScrollPane fx:id="playerSide" fitToWidth="true"
style="-fx-background: transparent; -fx-background-color: transparent;" hbarPolicy="NEVER" style="-fx-background: transparent; -fx-background-color: transparent;" hbarPolicy="NEVER"
vbarPolicy="AS_NEEDED" VBox.vgrow="ALWAYS"> vbarPolicy="AS_NEEDED" VBox.vgrow="ALWAYS">
<VBox.margin> <VBox.margin>
<Insets top="5"/> <Insets top="5"/>
</VBox.margin> </VBox.margin>
</ScrollPane> </ScrollPane>
<Pane HBox.hgrow="ALWAYS"/> <Pane HBox.hgrow="ALWAYS"/>
<HBox alignment="CENTER" fx:id="buttonRow" > <HBox alignment="CENTER" fx:id="buttonRow" >
<HBox spacing="10"> <HBox spacing="10">
<Button fx:id="skipBtn" styleClass="action-button" text="Skip Turn"/> <Button fx:id="skipBtn" styleClass="action-button" text="Skip Turn"/>
<Button fx:id="detailsBtn" styleClass="action-button" text="Ending Details"/> <Button fx:id="detailsBtn" styleClass="action-button" text="Ending Details"/>
</HBox> </HBox>
<VBox.margin> <VBox.margin>
<Insets top="5" right="5" bottom="5" left="5"/> <Insets top="5" right="5" bottom="5" left="5"/>
</VBox.margin> </VBox.margin>
</HBox> </HBox>
</children> </children>
</VBox> </VBox>
</children> </children>
</HBox> </HBox>
+2 -2
View File
@@ -35,11 +35,11 @@
} }
.player-card { .player-card {
-fx-border-color: #6a040f; -fx-border-color: #711423;
-fx-border-width: 2; -fx-border-width: 2;
-fx-border-radius: 15; -fx-border-radius: 15;
-fx-background-radius: 15; -fx-background-radius: 15;
-fx-background-color: #f48c06; -fx-background-color: #f18f1c;
} }
.frame { .frame {