diff --git a/.idea/misc.xml b/.idea/misc.xml index a2cda41..078a25f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + - + \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/LoginFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LoginFXMLController.java index 287874b..a6aa093 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/LoginFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/LoginFXMLController.java @@ -3,29 +3,36 @@ package it.polimi.ingsw.gc14.View.GUI; import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient; import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient; +import javafx.animation.*; import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.geometry.Rectangle2D; import javafx.scene.control.*; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.*; import javafx.scene.paint.Color; +import javafx.stage.Screen; +import javafx.util.Duration; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.util.ArrayList; +import java.net.*; import java.util.Enumeration; -import java.util.List; public class LoginFXMLController { + @FXML private ImageView backgroundImage; @FXML private TextField campoNome; @FXML private TextField campoNumPlayers; @FXML private TextField campoIP; - @FXML private RadioButton btnRMI; - @FXML private RadioButton btnTCP; @FXML private Button btnAccedi; @FXML private Label labelErrore; - @FXML private ComboBox comboInterfaccia; + @FXML private VBox formPanel; + @FXML private StackPane protocolToggle; + @FXML private Region toggleThumb; + @FXML private Label labelRMI; + @FXML private Label labelTCP; + private boolean isRMI = true; private ClientController controller; public void setController(ClientController controller) { @@ -34,83 +41,155 @@ public class LoginFXMLController { @FXML public void initialize() { - ToggleGroup group = new ToggleGroup(); - btnRMI.setToggleGroup(group); - btnTCP.setToggleGroup(group); + // Background + Image img = new Image(getClass().getResourceAsStream("/GUIImages/Background.png")); + backgroundImage.setImage(img); + Rectangle2D screenBounds = Screen.getPrimary().getBounds(); + backgroundImage.setFitWidth(screenBounds.getWidth()); + backgroundImage.setFitHeight(screenBounds.getHeight()); + + // Protocol toggle + protocolToggle.setOnMouseClicked(e -> switchProtocol()); + protocolToggle.setStyle(protocolToggle.getStyle() + " -fx-cursor: hand;"); + + // Button hover + final String BASE_BTN = btnAccedi.getStyle(); + btnAccedi.setOnMouseEntered(e -> btnAccedi.setStyle(BASE_BTN + + "-fx-effect: dropshadow(gaussian, rgba(244,192,90,0.45), 18, 0, 0, 0);")); + btnAccedi.setOnMouseExited(e -> btnAccedi.setStyle(BASE_BTN)); - new Thread(() -> { - try { - List ips = new ArrayList<>(); - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface ni = interfaces.nextElement(); - if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue; - Enumeration addresses = ni.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress addr = addresses.nextElement(); - if (addr instanceof Inet4Address) - ips.add(ni.getDisplayName() + " -> " + addr.getHostAddress()); - } - } - Platform.runLater(() -> { - comboInterfaccia.getItems().addAll(ips); - if (!ips.isEmpty()) comboInterfaccia.getSelectionModel().selectFirst(); - }); - } catch (Exception e) { - Platform.runLater(() -> labelErrore.setText("Errore nel rilevare le interfacce.")); - } - }).start(); btnAccedi.setOnAction(e -> onAccediClick()); } + private void switchProtocol() { + isRMI = !isRMI; + + TranslateTransition tt = new TranslateTransition(Duration.millis(200), toggleThumb); + tt.setToX(isRMI ? 0 : 110); + tt.play(); + + labelRMI.setStyle("-fx-font-family: 'Cinzel'; -fx-font-size: 11; -fx-font-weight: bold;" + + "-fx-text-fill: " + (isRMI ? "#0c0601" : "rgba(244,192,90,0.55)") + ";"); + labelTCP.setStyle("-fx-font-family: 'Cinzel'; -fx-font-size: 11; -fx-font-weight: bold;" + + "-fx-text-fill: " + (isRMI ? "rgba(244,192,90,0.55)" : "#0c0601") + ";"); + } + @FXML private void onAccediClick() { String nome = campoNome.getText().trim(); - controller.setMyUsername(nome); String ip = campoIP.getText().trim(); + + if (nome.isEmpty()) { + showError("Please select a name."); + return; + } + int numPlayers; try { numPlayers = Integer.parseInt(campoNumPlayers.getText().trim()); } catch (NumberFormatException e) { - labelErrore.setText("Numero giocatori non valido."); + showError("Invalid number of players."); return; } - if (nome.isEmpty() || ip.isEmpty()) { - labelErrore.setText("Compila tutti i campi."); - return; - } - System.setProperty("java.rmi.server.hostname", ip); + controller.setMyUsername(nome); - int networkType = btnRMI.isSelected() ? 0 : 1; - String interfaccia = getInterfaccia(); - - // Stesso thread di rete che era in ClientLauncher + // Resolve the local interface to use, then connect new Thread(() -> { - if (networkType == 0) { - RMIClient client = new RMIClient(controller, ip, 1099, interfaccia); - if (client.connect(nome, numPlayers)) { - controller.setClient(client); - Platform.runLater(() ->{ labelErrore.setTextFill(Color.GREEN); labelErrore.setText("Connected successfully! Waiting other players");}); - } else { - Platform.runLater(() ->{ labelErrore.setTextFill(Color.RED); labelErrore.setText("Connection RMI failed.");}); - } - } else { - TCPClient client = new TCPClient(controller, ip, 8080, 8081); - if (client.connect(nome, numPlayers)) { - controller.setClient(client); - Platform.runLater(() ->{ labelErrore.setTextFill(Color.GREEN); labelErrore.setText("Connected successfully! Waiting other players");}); - } else { - Platform.runLater(() ->{ labelErrore.setTextFill(Color.RED); labelErrore.setText("Connection TCP failed.");}); - } + try { + String localInterface = resolveLocalInterface(ip); + System.setProperty("java.rmi.server.hostname", localInterface); + connect(nome, ip, numPlayers, localInterface); + } catch (Exception ex) { + Platform.runLater(() -> showError("Network error: " + ex.getMessage())); } }).start(); - } - private String getInterfaccia() { - String selected = comboInterfaccia.getValue(); - if (selected == null) return ""; - return selected.contains("->") ? selected.split("->")[1].trim() : selected; + /** + * Given the server IP, finds the local network interface whose subnet + * contains that IP. Falls back to the default route for non-LAN addresses. + * Handles "localhost" and "127.x.x.x" explicitly. + */ + private String resolveLocalInterface(String serverIp) throws Exception { + // localhost shortcut + if (serverIp.equalsIgnoreCase("localhost") || + serverIp.startsWith("127.") || serverIp.isEmpty()) { + return "127.0.0.1"; + } + + InetAddress serverAddr = InetAddress.getByName(serverIp); + + // Walk every local interface and check if serverAddr is in its subnet + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { + NetworkInterface ni = ifaces.nextElement(); + if (!ni.isUp() || ni.isLoopback()) continue; + + for (InterfaceAddress ia : ni.getInterfaceAddresses()) { + InetAddress localAddr = ia.getAddress(); + if (!(localAddr instanceof Inet4Address)) continue; + + int prefix = ia.getNetworkPrefixLength(); + if (sameSubnet(localAddr, serverAddr, prefix)) { + return localAddr.getHostAddress(); + } + } + } + + // No subnet match — use the address the OS would naturally pick + // by opening a UDP socket toward the server (no data is sent) + try (DatagramSocket socket = new DatagramSocket()) { + socket.connect(serverAddr, 9); // port 9 = discard, never actually used + return socket.getLocalAddress().getHostAddress(); + } + } + + /** + * Returns true if {@code a} and {@code b} are in the same /prefix subnet. + */ + private boolean sameSubnet(InetAddress a, InetAddress b, int prefix) { + if (prefix < 0 || prefix > 32) return false; + int maskBits = prefix == 0 ? 0 : (0xFFFFFFFF << (32 - prefix)); + int addrA = toInt(a.getAddress()) & maskBits; + int addrB = toInt(b.getAddress()) & maskBits; + return addrA == addrB; + } + + private int toInt(byte[] bytes) { + return ((bytes[0] & 0xFF) << 24) | + ((bytes[1] & 0xFF) << 16) | + ((bytes[2] & 0xFF) << 8) | + (bytes[3] & 0xFF); + } + + private void connect(String nome, String ip, int numPlayers, String localInterface) { + if (isRMI) { + RMIClient client = new RMIClient(controller, ip, 1099, localInterface); + if (client.connect(nome, numPlayers)) { + controller.setClient(client); + Platform.runLater(() -> showSuccess("Connected! Waiting for other players…")); + } else { + Platform.runLater(() -> showError("RMI connection failed.")); + } + } else { + TCPClient client = new TCPClient(controller, ip, 8080, 8081); + if (client.connect(nome, numPlayers)) { + controller.setClient(client); + Platform.runLater(() -> showSuccess("Connected! Waiting for other players…")); + } else { + Platform.runLater(() -> showError("TCP connection failed.")); + } + } + } + + private void showError(String msg) { + labelErrore.setTextFill(Color.web("#e05050")); + labelErrore.setText(msg); + } + + private void showSuccess(String msg) { + labelErrore.setTextFill(Color.web("#6fcf8a")); + labelErrore.setText(msg); } } \ No newline at end of file diff --git a/src/main/resources/GUIScene/login.fxml b/src/main/resources/GUIScene/login.fxml index c9219e4..cec5843 100644 --- a/src/main/resources/GUIScene/login.fxml +++ b/src/main/resources/GUIScene/login.fxml @@ -1,31 +1,150 @@ - + + + - + - + + + + + + + + + + + + + -