diff --git a/src/main/java/de/bixilon/minosoft/Launcher.java b/src/main/java/de/bixilon/minosoft/Launcher.java index 88e6e3cde..59eb73b5b 100644 --- a/src/main/java/de/bixilon/minosoft/Launcher.java +++ b/src/main/java/de/bixilon/minosoft/Launcher.java @@ -13,6 +13,8 @@ package de.bixilon.minosoft; +import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Version; +import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Versions; import de.bixilon.minosoft.gui.main.GUITools; import de.bixilon.minosoft.gui.main.Server; import de.bixilon.minosoft.gui.main.ServerListCell; @@ -24,6 +26,9 @@ import javafx.scene.control.ListView; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; +import java.util.Comparator; +import java.util.Map; + public class Launcher extends Application { @@ -33,6 +38,18 @@ public class Launcher extends Application { @Override public void start(Stage primaryStage) { + GUITools.versions.add(Versions.getLowestVersionSupported()); + for (Map.Entry version : Versions.getVersionMap().entrySet()) { + GUITools.versions.add(version.getValue()); + } + Comparator comparator = Comparator.comparingInt(Version::getProtocolVersion); + FXCollections.sort(GUITools.versions, comparator); + GUITools.versions.sort((a, b) -> { + if (a.getProtocolVersion() == -1) { + return -Integer.MAX_VALUE; + } + return (b.getProtocolVersion() - a.getProtocolVersion()); + }); ListView listView = new ListView<>(); listView.setCellFactory((lv) -> ServerListCell.newInstance()); @@ -40,7 +57,7 @@ public class Launcher extends Application { servers.addAll(Minosoft.serverList); listView.setItems(servers); - Scene scene = new Scene(new BorderPane(listView), 400, 450); + Scene scene = new Scene(new BorderPane(listView), 550, 800); primaryStage.setScene(scene); primaryStage.setTitle("Minosoft"); primaryStage.getIcons().add(GUITools.logo); diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Version.java b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Version.java index 1ee51f515..b74036daf 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Version.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Version.java @@ -81,6 +81,9 @@ public class Version { if (super.equals(obj)) { return true; } + if (obj == null) { + return false; + } if (hashCode() != obj.hashCode()) { return false; } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java index 9ac430345..71297322f 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java @@ -151,6 +151,10 @@ public class Versions { } public static Version getLowestVersionSupported() { - return new Version("13w41b", 0, null, null); + return new Version("Automatic", -1, null, null); + } + + public static HashBiMap getVersionMap() { + return versionMap; } } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java index 7effef3c4..a1d2aee9e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java @@ -13,6 +13,9 @@ package de.bixilon.minosoft.gui.main; +import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Version; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.scene.image.Image; import java.io.ByteArrayInputStream; @@ -20,6 +23,7 @@ import java.util.Base64; public class GUITools { public final static Image logo = new Image(GUITools.class.getResourceAsStream("/icons/windowIcon.png")); + public final static ObservableList versions = FXCollections.observableArrayList(); public static Image getImageFromBase64(String base64) { if (base64 == null) { diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java index 5fa30feb4..2a62d5842 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java @@ -17,19 +17,24 @@ import de.bixilon.minosoft.Minosoft; import de.bixilon.minosoft.game.datatypes.Player; import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Version; import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Versions; +import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.protocol.ConnectionReasons; +import de.bixilon.minosoft.util.DNSUtil; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.MenuItem; +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; +import javafx.util.Callback; +import javafx.util.Pair; import java.io.IOException; import java.net.URL; @@ -57,7 +62,7 @@ public class ServerListCell extends ListCell implements Initializable { private Label serverName; @FXML private AnchorPane root; - private Server model; + private Server server; public static ServerListCell newInstance() { FXMLLoader loader = new FXMLLoader(ServerListCell.class.getResource("/layout/cells/server.fxml")); @@ -87,15 +92,21 @@ public class ServerListCell extends ListCell implements Initializable { protected void updateItem(Server server, boolean empty) { super.updateItem(server, empty); getRoot().getChildrenUnmodifiable().forEach(c -> c.setVisible(!empty)); - if (!empty && server != null && !server.equals(this.model)) { + if (!empty && server != null && !server.equals(this.server)) { + this.server = server; serverName.setText(server.getName()); Image favicon = server.getFavicon(); if (favicon == null) { favicon = GUITools.logo; } icon.setImage(favicon); + optionsConnect.setOnAction(e -> { + Connection connection = new Connection(Connection.lastConnectionId++, server.getAddress(), new Player(Minosoft.accountList.get(0))); + connection.resolve(ConnectionReasons.CONNECT); + }); + optionsEdit.setOnAction(e -> edit()); - Connection connection = new Connection(server.getId(), server.getAddress(), new Player(Minosoft.accountList.get(0))); + Connection connection = new Connection(Connection.lastConnectionId++, server.getAddress(), null); connection.addPingCallback(ping -> Platform.runLater(() -> { if (ping == null) { // Offline @@ -105,7 +116,12 @@ public class ServerListCell extends ListCell implements Initializable { return; } players.setText(String.format("%d/%d", ping.getPlayerOnline(), ping.getMaxPlayers())); - Version serverVersion = Versions.getVersionById(ping.getProtocolNumber()); + Version serverVersion; + if (server.getDesiredVersion() == -1) { + serverVersion = Versions.getVersionById(ping.getProtocolNumber()); + } else { + serverVersion = Versions.getVersionById(server.getDesiredVersion()); + } if (serverVersion == null) { version.setText(ping.getServerVersion()); version.setTextFill(Color.RED); @@ -120,13 +136,93 @@ public class ServerListCell extends ListCell implements Initializable { icon.setImage(ping.getFavicon()); } })); - connection.resolve(ConnectionReasons.PING); // resolve dns address and connect + connection.resolve(ConnectionReasons.PING); // resolve dns address and ping } - this.model = server; } @Override public void updateSelected(boolean selected) { super.updateSelected(selected); } + + public void edit() { + // Create the custom dialog. + Dialog> dialog = new Dialog<>(); + dialog.setTitle("Edit server: " + server.getName()); + dialog.setHeaderText("Edit the details of the server"); + + +// Set the button types. + ButtonType loginButtonType = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE); + dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL); + +// Create the username and password labels and fields. + GridPane grid = new GridPane(); + grid.setHgap(10); + grid.setVgap(10); + grid.setPadding(new Insets(20, 300, 10, 10)); + + TextField serverName = new TextField(); + serverName.setPromptText("Servername"); + serverName.setText(server.getName()); + TextField serverAddress = new TextField(); + serverAddress.setPromptText("Server address"); + serverAddress.setText(server.getAddress()); + + ComboBox versionList = new ComboBox<>(GUITools.versions); + versionList.setCellFactory(new Callback<>() { + @Override + public ListCell call(ListView p) { + return new ListCell<>() { + @Override + protected void updateItem(Version version, boolean empty) { + super.updateItem(version, empty); + if (!empty && version != null) { + setText(String.format("%s (%d)", version.getVersionName(), version.getProtocolVersion())); + } + } + }; + } + }); + if (server.getDesiredVersion() == -1) { + versionList.getSelectionModel().select(Versions.getLowestVersionSupported()); + } else { + versionList.getSelectionModel().select(Versions.getVersionById(server.getDesiredVersion())); + } + + grid.add(new Label("Servername:"), 0, 0); + grid.add(serverName, 1, 0); + grid.add(new Label("Server address:"), 0, 1); + grid.add(serverAddress, 1, 1); + grid.add(new Label("Version:"), 0, 2); + grid.add(versionList, 1, 2); + +// Enable/Disable login button depending on whether a username was entered. + Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType); + +// Do some validation (using the Java 8 lambda syntax). + serverAddress.textProperty().addListener((observable, oldValue, newValue) -> { + loginButton.setDisable(newValue.trim().isEmpty()); + }); + + dialog.getDialogPane().setContent(grid); + +// Request focus on the username field by default. + Platform.runLater(serverName::requestFocus); + +// Convert the result to a username-password-pair when the login button is clicked. + dialog.setResultConverter(dialogButton -> { + if (dialogButton == loginButtonType) { + ServerListCell.this.serverName.setText(serverName.getText()); + ServerListCell.this.server.setName(serverName.getText()); + ServerListCell.this.server.setDesiredVersion(versionList.getSelectionModel().getSelectedItem().getProtocolVersion()); + ServerListCell.this.server.setAddress(DNSUtil.correctHostName(serverAddress.getText())); + ServerListCell.this.server.saveToConfig(); + Log.info(String.format("Edited and saved server (serverName=%s, serverAddress=%s, version=%d)", server.getName(), server.getAddress(), server.getDesiredVersion())); + } + return null; + }); + + dialog.showAndWait(); + } } \ No newline at end of file diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java index 70bbd0125..625320446 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java @@ -41,6 +41,7 @@ import org.xbill.DNS.TextParseException; import java.util.ArrayList; public class Connection { + public static int lastConnectionId; final ArrayList addresses; final Network network = new Network(this); final PacketHandler handler = new PacketHandler(this); @@ -352,4 +353,5 @@ public class Connection { callback.handle(ping); } } + } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java index 0e3658231..f3db82a42 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java @@ -54,7 +54,7 @@ public class InByteBuffer { public byte readByte() { byte ret; ret = bytes[pos]; - pos = pos + 1; + pos++; return ret; } diff --git a/src/main/java/de/bixilon/minosoft/util/DNSUtil.java b/src/main/java/de/bixilon/minosoft/util/DNSUtil.java index e09e809dd..4f55fc4b9 100644 --- a/src/main/java/de/bixilon/minosoft/util/DNSUtil.java +++ b/src/main/java/de/bixilon/minosoft/util/DNSUtil.java @@ -52,7 +52,7 @@ public final class DNSUtil { } - public String correctHostName(String hostname) { + public static String correctHostName(String hostname) { // replaces invalid chars to avoid copy and paste issues (like spaces, ...) hostname = hostname.replaceAll("\\s", ""); return hostname; diff --git a/src/main/resources/layout/main.fxml b/src/main/resources/layout/main.fxml new file mode 100644 index 000000000..80a46f074 --- /dev/null +++ b/src/main/resources/layout/main.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + +