From 0d07a308c88830d11e42a27bf108af257bb353b4 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 21 Apr 2021 00:42:33 +0200 Subject: [PATCH] modding: improve code and performance of callback event invoker, convert ServerListCell to kotlin --- .../de/bixilon/minosoft/gui/main/Server.java | 12 +- .../minosoft/gui/main/ServerListCell.java | 451 ------------------ .../minosoft/gui/main/ServerListCell.kt | 358 ++++++++++++++ .../minosoft/gui/main/SessionListCell.java | 115 ----- .../minosoft/gui/main/SessionListCell.kt | 101 ++++ .../minosoft/gui/rendering/RenderWindow.kt | 6 +- .../gui/rendering/chunk/WorldRenderer.kt | 8 +- .../modding/event/CallbackEventInvoker.java | 47 -- .../modding/event/CallbackEventInvoker.kt | 43 ++ .../protocol/network/connection/Connection.kt | 3 + .../network/connection/StatusConnection.kt | 5 +- 11 files changed, 521 insertions(+), 628 deletions(-) delete mode 100644 src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java create mode 100644 src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt delete mode 100644 src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java create mode 100644 src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt delete mode 100644 src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.kt diff --git a/src/main/java/de/bixilon/minosoft/gui/main/Server.java b/src/main/java/de/bixilon/minosoft/gui/main/Server.java index 8acc420be..7722b4292 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/Server.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/Server.java @@ -39,7 +39,7 @@ public class Server { private int desiredVersion; private byte[] favicon; private StatusConnection lastPing; - private boolean readOnly; + private boolean temporary; private ServerListCell cell; public Server(int id, ChatComponent name, String address, int desiredVersion, byte[] favicon) { @@ -67,7 +67,7 @@ public class Server { this.name = ChatComponent.Companion.valueOf(String.format("LAN Server #%d", LANServerListener.getServerMap().size())); this.address = address.toString(); this.desiredVersion = -1; // Automatic - this.readOnly = true; + this.temporary = true; } public static int getNextServerId() { @@ -96,7 +96,7 @@ public class Server { } public void saveToConfig() { - if (isReadOnly()) { + if (isTemporary()) { return; } Minosoft.getConfig().getConfig().getServer().getEntries().put(this.getId(), this); @@ -104,7 +104,7 @@ public class Server { } public void delete() { - if (isReadOnly()) { + if (isTemporary()) { return; } Minosoft.getConfig().getConfig().getServer().getEntries().remove(this.getId()); @@ -197,8 +197,8 @@ public class Server { return Base64.getEncoder().encodeToString(this.favicon); } - public boolean isReadOnly() { - return this.readOnly; + public boolean isTemporary() { + return this.temporary; } public ServerListCell getCell() { diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java deleted file mode 100644 index a8db2da52..000000000 --- a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2020 Moritz Zwerger - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.gui.main; - -import com.jfoenix.controls.JFXAlert; -import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialogLayout; -import de.bixilon.minosoft.Minosoft; -import de.bixilon.minosoft.data.locale.LocaleManager; -import de.bixilon.minosoft.data.locale.Strings; -import de.bixilon.minosoft.data.mappings.ResourceLocation; -import de.bixilon.minosoft.data.mappings.versions.Version; -import de.bixilon.minosoft.data.mappings.versions.Versions; -import de.bixilon.minosoft.data.player.tab.PingBars; -import de.bixilon.minosoft.data.text.ChatComponent; -import de.bixilon.minosoft.modding.event.CallbackEventInvoker; -import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent; -import de.bixilon.minosoft.modding.event.events.ServerListPongEvent; -import de.bixilon.minosoft.modding.event.events.ServerListStatusArriveEvent; -import de.bixilon.minosoft.protocol.network.connection.PlayConnection; -import de.bixilon.minosoft.protocol.ping.ForgeModInfo; -import de.bixilon.minosoft.protocol.ping.ServerListPing; -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition; -import de.bixilon.minosoft.util.CountUpAndDownLatch; -import de.bixilon.minosoft.util.logging.Log; -import javafx.application.Platform; -import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; -import javafx.scene.Node; -import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; -import javafx.scene.paint.Color; -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; -import javafx.stage.Modality; - -import java.io.IOException; -import java.net.URL; -import java.util.Arrays; -import java.util.ResourceBundle; - -public class ServerListCell extends ListCell implements Initializable { - public static final ListView SERVER_LIST_VIEW = new ListView<>(); - - public HBox hBox; - public GridPane root; - - public ImageView faviconField; - public TextFlow nameField; - public TextFlow motdField; - public Label versionField; - public Label playersField; - public Label brandField; - - public MenuItem optionsConnect; - public MenuItem optionsShowInfo; - public MenuItem optionsEdit; - public MenuItem optionsRefresh; - public MenuItem optionsSessions; - public MenuItem optionsDelete; - public MenuButton optionsMenu; - public Label pingField; - - private boolean canConnect; - private Server server; - - public static ServerListCell newInstance() { - FXMLLoader loader = new FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(new ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/server.fxml"))); - try { - loader.load(); - return loader.getController(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public void initialize(URL url, ResourceBundle rb) { - updateSelected(false); - setGraphic(this.root); - - // change locale - this.optionsConnect.setText(LocaleManager.translate(Strings.SERVER_ACTION_CONNECT)); - this.optionsShowInfo.setText(LocaleManager.translate(Strings.SERVER_ACTION_SHOW_INFO)); - this.optionsEdit.setText(LocaleManager.translate(Strings.SERVER_ACTION_EDIT)); - this.optionsRefresh.setText(LocaleManager.translate(Strings.SERVER_ACTION_REFRESH)); - this.optionsSessions.setText(LocaleManager.translate(Strings.SERVER_ACTION_SESSIONS)); - this.optionsDelete.setText(LocaleManager.translate(Strings.SERVER_ACTION_DELETE)); - } - - @Override - protected void updateItem(Server server, boolean empty) { - super.updateItem(server, empty); - - this.root.setVisible(server != null || !empty); - this.hBox.setVisible(server != null || !empty); - if (empty) { - return; - } - - if (server == null) { - return; - } - if (this.server != server) { - resetCell(); - } - server.setCell(this); - - this.server = server; - setName(server.getName()); - - Image favicon = GUITools.getImage(server.getFavicon()); - if (favicon == null) { - favicon = GUITools.MINOSOFT_LOGO; - } - this.faviconField.setImage(favicon); - if (server.isConnected()) { - this.root.getStyleClass().add("list-cell-connected"); - this.optionsSessions.setDisable(false); - } else { - this.optionsSessions.setDisable(true); - } - if (server.getLastPing() == null) { - server.ping(); - } - - server.getLastPing().registerEvent(new CallbackEventInvoker(event -> Platform.runLater(() -> { - ServerListPing ping = event.getServerListPing(); - if (server != this.server) { - // cell does not contains us anymore - return; - } - resetCell(); - - if (server.isConnected()) { - this.root.getStyleClass().add("list-cell-connected"); - } - if (ping == null) { - // Offline - this.playersField.setText(""); - this.versionField.setText(LocaleManager.translate(Strings.OFFLINE)); - this.versionField.getStyleClass().add("version-error"); - setErrorMotd(String.format("%s", server.getLastPing().getLastException())); - this.optionsConnect.setDisable(true); - this.canConnect = false; - return; - } - this.playersField.setText(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.getPlayerOnline(), ping.getMaxPlayers())); - Version serverVersion; - if (server.getDesiredVersionId() == ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID) { - serverVersion = Versions.getVersionByProtocolId(ping.getProtocolId()); - } else { - serverVersion = Versions.getVersionById(server.getDesiredVersionId()); - this.versionField.setStyle("-fx-text-fill: -secondary-light-light-color;"); - } - if (serverVersion == null) { - this.versionField.setText(ping.getServerBrand()); - this.versionField.setStyle("-fx-text-fill: red;"); - this.optionsConnect.setDisable(true); - this.canConnect = false; - } else { - this.versionField.setText(serverVersion.getVersionName()); - this.optionsConnect.setDisable(false); - this.canConnect = true; - } - this.brandField.setText(ping.getServerModInfo().getBrand()); - this.brandField.setTooltip(new Tooltip(ping.getServerModInfo().getInfo())); - this.motdField.getChildren().setAll(ping.getMotd().getJavaFXText()); - if (ping.getFavicon() != null) { - this.faviconField.setImage(GUITools.getImage(ping.getFavicon())); - if (!Arrays.equals(ping.getFavicon(), server.getFavicon())) { - server.setFavicon(ping.getFavicon()); - server.saveToConfig(); - } - } - if (server.isReadOnly()) { - this.optionsEdit.setDisable(true); - this.optionsDelete.setDisable(true); - } - if (server.getLastPing().getLastException() != null) { - // connection failed because of an error in minosoft, but ping was okay - this.versionField.setStyle("-fx-text-fill: red;"); - this.optionsConnect.setDisable(true); - this.canConnect = false; - setErrorMotd(String.format("%s: %s", server.getLastPing().getLastException().getClass().getCanonicalName(), server.getLastPing().getLastException().getMessage())); - } - }))); - server.getLastPing().registerEvent(new CallbackEventInvoker(event -> Platform.runLater(() -> { - this.pingField.setText(String.format("%dms", event.getLatency())); - switch (PingBars.byPing(event.getLatency())) { - case BARS_5 -> this.pingField.getStyleClass().add("ping-5-bars"); - case BARS_4 -> this.pingField.getStyleClass().add("ping-4-bars"); - case BARS_3 -> this.pingField.getStyleClass().add("ping-3-bars"); - case BARS_2 -> this.pingField.getStyleClass().add("ping-2-bars"); - case BARS_1 -> this.pingField.getStyleClass().add("ping-1-bars"); - case NO_CONNECTION -> this.pingField.getStyleClass().add("ping-no-connection"); - } - }))); - } - - public void setName(ChatComponent name) { - this.nameField.getChildren().setAll(name.getJavaFXText()); - for (Node node : this.nameField.getChildren()) { - node.setStyle("-fx-font-size: 15pt ;"); - } - } - - private void resetCell() { - // clear all cells - setStyle(null); - this.root.getStyleClass().removeAll("list-cell-connected"); - this.root.getStyleClass().removeAll("list-cell-connecting"); - this.motdField.getChildren().clear(); - this.brandField.setText(""); - this.brandField.setTooltip(null); - this.motdField.setStyle(null); - this.versionField.setText(LocaleManager.translate(Strings.CONNECTING)); - this.versionField.getStyleClass().removeAll("version-error"); - this.versionField.setStyle(null); - this.playersField.setText(""); - this.pingField.setText(""); - this.pingField.getStyleClass().removeIf((s -> s.startsWith("ping"))); - this.optionsConnect.setDisable(true); - this.optionsEdit.setDisable(false); - this.optionsDelete.setDisable(false); - } - - private void setErrorMotd(String message) { - Text text = new Text(message); - text.setFill(Color.RED); - this.motdField.getChildren().setAll(text); - } - - public void delete() { - if (this.server.isReadOnly()) { - return; - } - this.server.getConnections().forEach(PlayConnection::disconnect); - this.server.delete(); - Log.info(String.format("Deleted server (name=\"%s\", address=\"%s\")", this.server.getName().getLegacyText(), this.server.getAddress())); - SERVER_LIST_VIEW.getItems().remove(this.server); - } - - public void refresh() { - if (this.server.getLastPing() == null) { - // server was not pinged, don't even try, only costs memory and cpu - return; - } - Log.info(String.format("Refreshing server status (serverName=\"%s\", address=\"%s\")", this.server.getName().getLegacyText(), this.server.getAddress())); - resetCell(); - this.server.ping(); - } - - public void clicked(MouseEvent e) { - switch (e.getButton()) { - case PRIMARY -> { - if (e.getClickCount() == 2) { - connect(); - } - } - case SECONDARY -> this.optionsMenu.fire(); - case MIDDLE -> { - SERVER_LIST_VIEW.getSelectionModel().select(this.server); - editServer(); - } - } - } - - public void connect() { - if (!this.canConnect || this.server.getLastPing() == null) { - return; - } - if (this.server.isConnected()) { - return; - } - this.root.getStyleClass().add("list-cell-connecting"); - Minosoft.THREAD_POOL.execute(() -> { - Version version; - if (this.server.getDesiredVersionId() == ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID) { - version = this.server.getLastPing().getServerVersion(); - } else { - version = Versions.getVersionById(this.server.getDesiredVersionId()); - } - - PlayConnection connection = new PlayConnection(this.server.getLastPing().getRealAddress(), Minosoft.getConfig().getConfig().getAccount().getEntries().get(Minosoft.getConfig().getConfig().getAccount().getSelected()), version); - this.server.addConnection(connection); - Platform.runLater(() -> { - this.optionsConnect.setDisable(true); - }); - // ToDo: show progress dialog - - connection.registerEvent(new CallbackEventInvoker<>(this::handleConnectionCallback)); - connection.connect(new CountUpAndDownLatch(1)); - }); - } - - public void editServer() { - MainWindow.addOrEditServer(this.server); - } - - private void handleConnectionCallback(ConnectionStateChangeEvent event) { - PlayConnection connection = (PlayConnection) event.getConnection(); - if (!this.server.getConnections().contains(connection)) { - // the card got recycled - return; - } - Platform.runLater(() -> { - this.root.getStyleClass().removeAll("list-cell-connecting"); - this.root.getStyleClass().removeAll("list-cell-connected"); - this.root.getStyleClass().removeAll("list-cell-disconnecting"); - this.root.getStyleClass().removeAll("list-cell-failed"); - this.root.getStyleClass().add(switch (connection.getConnectionState()) { - case CONNECTING, HANDSHAKING, LOGIN -> "list-cell-connecting"; - case PLAY -> "list-cell-connected"; - case DISCONNECTING -> "list-cell-disconnecting"; - case FAILED, FAILED_NO_RETRY -> "list-cell-failed"; - default -> ""; - }); - - if (connection.isConnected()) { - this.optionsConnect.setDisable(Minosoft.getConfig().getConfig().getAccount().getSelected().equals(connection.getAccount().getId())); - this.optionsSessions.setDisable(false); - return; - } - - if (this.server.isConnected()) { - this.optionsSessions.setDisable(false); - this.optionsConnect.setDisable(false); - return; - } - - this.optionsConnect.setDisable(false); - this.optionsSessions.setDisable(true); - }); - } - - public void showInfo() { - JFXAlert dialog = new JFXAlert<>(); - dialog.setTitle("View server info: " + this.server.getName().getMessage()); - GUITools.initializePane(dialog.getDialogPane()); - - JFXDialogLayout layout = new JFXDialogLayout(); - - JFXButton closeButton = new JFXButton(ButtonType.CLOSE.getText()); - closeButton.setOnAction((actionEvent -> dialog.hide())); - closeButton.setButtonType(JFXButton.ButtonType.RAISED); - layout.setActions(closeButton); - - GridPane grid = new GridPane(); - grid.setHgap(10); - grid.setVgap(10); - - TextFlow serverNameLabel = new TextFlow(); - serverNameLabel.getChildren().setAll(this.server.getName().getJavaFXText()); - Label serverAddressLabel = new Label(this.server.getAddress()); - Label forcedVersionLabel = new Label(); - - if (this.server.getDesiredVersionId() == ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID) { - forcedVersionLabel.setText(Versions.AUTOMATIC_VERSION.getVersionName()); - } else { - forcedVersionLabel.setText(Versions.getVersionById(this.server.getDesiredVersionId()).getVersionName()); - } - - int column = -1; - Label a = new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"); - a.setWrapText(false); - grid.add(a, 0, ++column); - grid.add(serverNameLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, ++column); - grid.add(serverAddressLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.FORCED_VERSION) + ":"), 0, ++column); - grid.add(forcedVersionLabel, 1, column); - - if (this.server.getLastPing() != null) { - if (this.server.getLastPing().getLastException() != null) { - Label lastConnectionExceptionLabel = new Label(this.server.getLastPing().getLastException().toString()); - lastConnectionExceptionLabel.setStyle("-fx-text-fill: red"); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_LAST_CONNECTION_EXCEPTION) + ":"), 0, ++column); - grid.add(lastConnectionExceptionLabel, 1, column); - } - - if (this.server.getLastPing().getLastPing() != null) { - ServerListPing lastPing = this.server.getLastPing().getLastPing(); - Version serverVersion = Versions.getVersionByProtocolId(lastPing.getProtocolId()); - String serverVersionString; - if (serverVersion == null) { - serverVersionString = LocaleManager.translate(Strings.SERVER_INFO_VERSION_UNKNOWN, lastPing.getProtocolId()); - } else { - serverVersionString = serverVersion.getVersionName(); - } - Label realServerAddressLabel = new Label(this.server.getLastPing().getAddress()); - Label serverVersionLabel = new Label(serverVersionString); - Label serverBrandLabel = new Label(lastPing.getServerBrand()); - Label playersOnlineMaxLabel = new Label(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, lastPing.getPlayerOnline(), lastPing.getMaxPlayers())); - TextFlow motdLabel = new TextFlow(); - motdLabel.getChildren().setAll(lastPing.getMotd().getJavaFXText()); - Label moddedBrandLabel = new Label(lastPing.getServerModInfo().getBrand()); - - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_REAL_SERVER_ADDRESS) + ":"), 0, ++column); - grid.add(realServerAddressLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, ++column); - grid.add(serverVersionLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_BRAND) + ":"), 0, ++column); - grid.add(serverBrandLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_PLAYERS_ONLINE) + ":"), 0, ++column); - grid.add(playersOnlineMaxLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_MESSAGE_OF_THE_DAY) + ":"), 0, ++column); - grid.add(motdLabel, 1, column); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_BRAND) + ":"), 0, ++column); - grid.add(moddedBrandLabel, 1, column); - - if (lastPing.getServerModInfo() instanceof ForgeModInfo forgeModInfo) { - Label moddedModsLabel = new Label(forgeModInfo.getModList().toString()); - moddedModsLabel.setWrapText(true); - - grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_SERVER_MODDED_MOD_LIST) + ":"), 0, ++column); - grid.add(moddedModsLabel, 1, column); - } - } - } - // ToDo: size probably - layout.setBody(grid); - dialog.setContent(layout); - dialog.showAndWait(); - } - - public void manageSessions() { - try { - SessionsWindow sessionsWindow = GUITools.showPane(new ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/sessions.fxml"), Modality.APPLICATION_MODAL, LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, this.server.getName().getMessage())); - sessionsWindow.setServer(this.server); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt new file mode 100644 index 000000000..1c137e2d3 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt @@ -0,0 +1,358 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.gui.main + +import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.data.locale.LocaleManager +import de.bixilon.minosoft.data.locale.Strings +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.versions.Version +import de.bixilon.minosoft.data.mappings.versions.Versions +import de.bixilon.minosoft.data.player.tab.PingBars +import de.bixilon.minosoft.data.text.ChatComponent +import de.bixilon.minosoft.modding.event.CallbackEventInvoker +import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent +import de.bixilon.minosoft.modding.event.events.ServerListPongEvent +import de.bixilon.minosoft.modding.event.events.ServerListStatusArriveEvent +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.protocol.ping.ServerModInfo +import de.bixilon.minosoft.protocol.protocol.ConnectionStates +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.CountUpAndDownLatch +import de.bixilon.minosoft.util.logging.Log +import javafx.application.Platform +import javafx.fxml.FXMLLoader +import javafx.fxml.Initializable +import javafx.scene.control.* +import javafx.scene.image.ImageView +import javafx.scene.input.MouseButton +import javafx.scene.input.MouseEvent +import javafx.scene.layout.GridPane +import javafx.scene.layout.HBox +import javafx.scene.paint.Color +import javafx.scene.text.Text +import javafx.scene.text.TextFlow +import javafx.stage.Modality +import java.net.URL +import java.util.* + + +class ServerListCell : ListCell(), Initializable { + lateinit var hBox: HBox + lateinit var root: GridPane + lateinit var faviconField: ImageView + lateinit var nameField: TextFlow + lateinit var motdField: TextFlow + lateinit var versionField: Label + lateinit var playersField: Label + lateinit var brandField: Label + lateinit var optionsConnect: MenuItem + lateinit var optionsShowInfo: MenuItem + lateinit var optionsEdit: MenuItem + lateinit var optionsRefresh: MenuItem + lateinit var optionsSessions: MenuItem + lateinit var optionsDelete: MenuItem + lateinit var optionsMenu: MenuButton + lateinit var pingField: Label + private var server: Server? = null + private var connectable = true + + private var _name: ChatComponent = ChatComponent.valueOf(raw = "") + + var name: ChatComponent + get() = _name + set(value) { + _name = value + nameField.children.setAll(name.javaFXText) + for (node in nameField.children) { + node.style = "-fx-font-size: 15pt ;" + } + } + + override fun initialize(url: URL, rb: ResourceBundle?) { + updateSelected(false) + graphic = this.root + + // change locale + optionsConnect.text = LocaleManager.translate(Strings.SERVER_ACTION_CONNECT) + optionsShowInfo.text = LocaleManager.translate(Strings.SERVER_ACTION_SHOW_INFO) + optionsEdit.text = LocaleManager.translate(Strings.SERVER_ACTION_EDIT) + optionsRefresh.text = LocaleManager.translate(Strings.SERVER_ACTION_REFRESH) + optionsSessions.text = LocaleManager.translate(Strings.SERVER_ACTION_SESSIONS) + optionsDelete.text = LocaleManager.translate(Strings.SERVER_ACTION_DELETE) + } + + override fun updateItem(server: Server?, empty: Boolean) { + super.updateItem(server, empty) + + this.root.isVisible = server != null || !empty + this.hBox.isVisible = server != null || !empty + + if (empty || server == null) { + return + } + + resetCell() + + server.cell = this + + this.server = server + + name = server.name + + faviconField.image = GUITools.getImage(server.favicon) ?: GUITools.MINOSOFT_LOGO + + if (server.isConnected) { + root.styleClass.add("list-cell-connected") + optionsSessions.isDisable = false + } else { + optionsSessions.isDisable = true + } + if (server.lastPing == null) { + server.ping() + } + + server.lastPing.registerEvent(CallbackEventInvoker.of { + Platform.runLater { + val ping = it.serverListPing + + if (this.server != server) { + // this cell does not belong here anymore + return@runLater + } + resetCell() + if (server.isConnected) { + root.styleClass.add("list-cell-connected") + } + if (ping == null) { + this.playersField.text = "" + this.versionField.text = LocaleManager.translate(Strings.OFFLINE) + this.versionField.styleClass.add("version-error") + setErrorMotd(server.lastPing.lastException.toString()) + this.optionsConnect.isDisable = true + this.connectable = false + return@runLater + } + + this.playersField.text = LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.playerOnline, ping.maxPlayers) + + val serverVersion: Version + + if (server.desiredVersionId == ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID) { + serverVersion = Versions.getVersionByProtocolId(ping.protocolId) + } else { + serverVersion = Versions.getVersionById(server.desiredVersionId) + versionField.style = "-fx-text-fill: -secondary-light-light-color;" + } + if (serverVersion == null) { + versionField.text = ping.serverBrand + versionField.style = "-fx-text-fill: red;" + optionsConnect.isDisable = true + connectable = false + } else { + versionField.text = serverVersion.versionName + optionsConnect.isDisable = false + connectable = true + } + + ping.getServerModInfo().let { modInfo -> + brandField.text = modInfo.brand + brandField.tooltip = Tooltip(modInfo.info) + } + motdField.children.setAll(ping.motd.javaFXText) + + ping.favicon?.let { + this.faviconField.image = GUITools.getImage(ping.favicon) + if (!Arrays.equals(ping.favicon, server.favicon)) { + server.favicon = ping.favicon + server.saveToConfig() + } + } + + if (server.isTemporary) { + this.optionsEdit.isDisable = true + this.optionsDelete.isDisable = true + } + + server.lastPing.lastException?.let { exception -> + // connection failed because of an error in minosoft, but ping was okay + this.versionField.style = "-fx-text-fill: red;" + this.optionsConnect.isDisable = true + this.connectable = false + setErrorMotd(String.format("%s: %s", exception::class.java.canonicalName, exception.message)) + } + + server.lastPing.registerEvent(CallbackEventInvoker.of { + Platform.runLater { + this.pingField.text = "${it.latency}ms" + when (PingBars.byPing(it.latency)) { + PingBars.BARS_5 -> this.pingField.styleClass.add("ping-5-bars") + PingBars.BARS_4 -> this.pingField.styleClass.add("ping-4-bars") + PingBars.BARS_3 -> this.pingField.styleClass.add("ping-3-bars") + PingBars.BARS_2 -> this.pingField.styleClass.add("ping-2-bars") + PingBars.BARS_1 -> this.pingField.styleClass.add("ping-1-bars") + PingBars.NO_CONNECTION -> this.pingField.styleClass.add("ping-no-connection") + } + } + }) + } + }) + } + + private fun resetCell() { + // clear all cells + style = null + this.root.styleClass.removeAll("list-cell-connected") + this.root.styleClass.removeAll("list-cell-connecting") + motdField.children.clear() + brandField.text = "" + brandField.tooltip = null + motdField.style = null + versionField.text = LocaleManager.translate(Strings.CONNECTING) + versionField.styleClass.removeAll("version-error") + versionField.style = null + playersField.text = "" + pingField.text = "" + pingField.styleClass.removeIf { s: String -> s.startsWith("ping") } + optionsConnect.isDisable = true + optionsEdit.isDisable = false + optionsDelete.isDisable = false + } + + private fun setErrorMotd(message: String) { + val text = Text(message) + text.fill = Color.RED + motdField.children.setAll(text) + } + + fun connect() { + val server = this.server!! + if (!this.connectable || server.lastPing == null) { + return + } + if (server.isConnected) { + return + } + this.root.styleClass.add("list-cell-connecting") + Minosoft.THREAD_POOL.execute { + val version: Version = if (server.desiredVersionId == ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID) { + server.lastPing.serverVersion!! + } else { + Versions.getVersionById(server.desiredVersionId) + } + val connection = PlayConnection(server.lastPing.realAddress, Minosoft.getConfig().config.account.entries[Minosoft.getConfig().config.account.selected]!!, version) + server.addConnection(connection) + Platform.runLater { optionsConnect.isDisable = true } + // ToDo: show progress dialog + connection.registerEvent(CallbackEventInvoker.of { + if (!server.connections.contains(connection)) { + // the card got recycled + return@of + } + Platform.runLater { + this.root.styleClass.removeAll("list-cell-connecting") + this.root.styleClass.removeAll("list-cell-connected") + this.root.styleClass.removeAll("list-cell-disconnecting") + this.root.styleClass.removeAll("list-cell-failed") + this.root.styleClass.add(when (connection.connectionState) { + ConnectionStates.CONNECTING, ConnectionStates.HANDSHAKING, ConnectionStates.LOGIN -> "list-cell-connecting" + ConnectionStates.PLAY -> "list-cell-connected" + ConnectionStates.DISCONNECTING -> "list-cell-disconnecting" + ConnectionStates.FAILED, ConnectionStates.FAILED_NO_RETRY -> "list-cell-failed" + else -> "" + }) + if (connection.isConnected) { + optionsConnect.isDisable = Minosoft.getConfig().config.account.selected == connection.account.id + optionsSessions.isDisable = false + return@runLater + } + if (server.isConnected) { + optionsSessions.isDisable = false + optionsConnect.isDisable = false + return@runLater + } + optionsConnect.isDisable = false + optionsSessions.isDisable = true + } + }) + connection.connect(CountUpAndDownLatch(1)) + } + } + + fun showInfo() { + TODO("Not implemented yet!") + } + + fun clicked(event: MouseEvent) { + when (event.button) { + MouseButton.PRIMARY -> { + if (event.clickCount == 2) { + connect() + } + } + MouseButton.SECONDARY -> this.optionsMenu.fire() + MouseButton.MIDDLE -> { + SERVER_LIST_VIEW.selectionModel.select(this.server) + editServer() + } + else -> { + } + } + } + + fun delete() { + val server = this.server!! + if (server.isTemporary) { + return + } + for (connection in server.connections) { + connection.disconnect() + } + server.delete() + Log.info("Deleted server (name=\"${server.name}\", address=\"${server.address}\")") + SERVER_LIST_VIEW.items.remove(server) + } + + fun refresh() { + val server = this.server!! + if (server.lastPing == null) { + // server was not pinged, don't even try, only costs memory and cpu + return + } + Log.info("Refreshing server status (serverName=\"${server.name}\", address=\"${server.address}\")") + resetCell() + server.ping() + } + + fun editServer() { + MainWindow.addOrEditServer(server) + } + + fun manageSessions() { + val sessionsWindow = GUITools.showPane(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/sessions.fxml"), Modality.APPLICATION_MODAL, LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, server!!.name.message)) + sessionsWindow.setServer(server) + } + + companion object { + @JvmField + val SERVER_LIST_VIEW = ListView() + + @JvmStatic + fun newInstance(): ServerListCell { + val loader = FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/server.fxml"))) + + loader.load() + return loader.getController() + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java deleted file mode 100644 index 297e4ba7a..000000000 --- a/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2020 Moritz Zwerger - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.gui.main; - -import de.bixilon.minosoft.Minosoft; -import de.bixilon.minosoft.data.locale.LocaleManager; -import de.bixilon.minosoft.data.locale.Strings; -import de.bixilon.minosoft.data.mappings.ResourceLocation; -import de.bixilon.minosoft.modding.event.CallbackEventInvoker; -import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent; -import de.bixilon.minosoft.protocol.network.connection.PlayConnection; -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition; -import javafx.application.Platform; -import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.MenuItem; -import javafx.scene.layout.AnchorPane; -import javafx.stage.Stage; - -import java.io.IOException; -import java.net.URL; -import java.util.ResourceBundle; - -public class SessionListCell extends ListCell implements Initializable { - public static final ListView CONNECTION_LIST_VIEW = new ListView<>(); - - public Label account; - public Label connectionId; - public MenuItem optionsDisconnect; - public AnchorPane root; - - private PlayConnection connection; - - public static SessionListCell newInstance() { - FXMLLoader loader = new FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(new ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/session.fxml"))); - try { - loader.load(); - return loader.getController(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public void initialize(URL url, ResourceBundle rb) { - updateSelected(false); - setGraphic(this.root); - - this.optionsDisconnect.setText(LocaleManager.translate(Strings.SESSIONS_ACTION_DISCONNECT)); - } - - public AnchorPane getRoot() { - return this.root; - } - - @Override - protected void updateItem(PlayConnection connection, boolean empty) { - super.updateItem(connection, empty); - - this.root.setVisible(!empty); - if (empty) { - return; - } - - if (connection == null) { - return; - } - - if (connection.equals(this.connection)) { - return; - } - setStyle(null); - this.connection = connection; - connection.registerEvent(new CallbackEventInvoker<>(this::handleConnectionCallback)); - this.connectionId.setText(String.format("#%d", connection.getConnectionId())); - this.account.setText(connection.getAccount().getUsername()); - } - - private void handleConnectionCallback(ConnectionStateChangeEvent event) { - PlayConnection connection = (PlayConnection) event.getConnection(); - if (this.connection != connection) { - // the card got recycled - return; - } - - if (!connection.isConnected()) { - Platform.runLater(() -> { - CONNECTION_LIST_VIEW.getItems().remove(connection); - if (CONNECTION_LIST_VIEW.getItems().isEmpty()) { - ((Stage) this.root.getScene().getWindow()).close(); - } - }); - } - } - - public void disconnect() { - setStyle("-fx-background-color: indianred"); - this.connection.disconnect(); - } -} diff --git a/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt b/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt new file mode 100644 index 000000000..4389e6846 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt @@ -0,0 +1,101 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.gui.main + +import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.data.locale.LocaleManager +import de.bixilon.minosoft.data.locale.Strings +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.modding.event.CallbackEventInvoker +import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import javafx.application.Platform +import javafx.fxml.FXMLLoader +import javafx.fxml.Initializable +import javafx.scene.control.Label +import javafx.scene.control.ListCell +import javafx.scene.control.ListView +import javafx.scene.control.MenuItem +import javafx.scene.layout.AnchorPane +import javafx.stage.Stage +import java.net.URL +import java.util.* + +class SessionListCell : ListCell(), Initializable { + lateinit var account: Label + lateinit var connectionId: Label + lateinit var optionsDisconnect: MenuItem + lateinit var root: AnchorPane + private var connection: PlayConnection? = null + + override fun initialize(url: URL, rb: ResourceBundle?) { + updateSelected(false) + graphic = this.root + optionsDisconnect.text = LocaleManager.translate(Strings.SESSIONS_ACTION_DISCONNECT) + } + + override fun updateItem(connection: PlayConnection?, empty: Boolean) { + super.updateItem(connection, empty) + this.root.isVisible = !empty + if (empty) { + return + } + if (connection == null) { + return + } + if (connection == this.connection) { + return + } + style = null + this.connection = connection + connection.registerEvent(CallbackEventInvoker.of { + handleConnectionCallback(it) + }) + connectionId.text = String.format("#%d", connection.connectionId) + account.text = connection.account.username + } + + private fun handleConnectionCallback(event: ConnectionStateChangeEvent) { + val connection = event.connection as PlayConnection + if (this.connection != connection) { + // the card got recycled + return + } + if (!connection.isConnected) { + Platform.runLater { + CONNECTION_LIST_VIEW.items.remove(connection) + if (CONNECTION_LIST_VIEW.items.isEmpty()) { + (this.root.scene.window as Stage).close() + } + } + } + } + + fun disconnect() { + style = "-fx-background-color: indianred" + connection!!.disconnect() + } + + companion object { + @JvmField + val CONNECTION_LIST_VIEW = ListView() + + @JvmStatic + fun newInstance(): SessionListCell? { + val loader = FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/session.fxml"))) + loader.load() + return loader.getController() + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index ae5c9a9b7..5c9f88f70 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -129,17 +129,17 @@ class RenderWindow( } init { - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { if (it.connection.isDisconnected) { renderQueue.add { glfwSetWindowShouldClose(windowId, true) } } }) - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { val packet = it.packet if (packet !is PacketPlayerPositionAndRotation) { - return@CallbackEventInvoker + return@of } if (latch.count > 0) { latch.countDown() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt index 790bcf40b..d5c4ec9b1 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt @@ -127,19 +127,19 @@ class WorldRenderer( prepareWorld(world) } - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { unloadChunk(it.chunkPosition) }) - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { prepareChunk(it.chunkPosition) }) - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { prepareChunkSection(it.blockPosition.chunkPosition, it.blockPosition.sectionHeight) }) - connection.registerEvent(CallbackEventInvoker { + connection.registerEvent(CallbackEventInvoker.of { val sectionHeights: MutableSet = mutableSetOf() for ((key) in it.blocks) { sectionHeights.add(key.sectionHeight) diff --git a/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.java b/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.java deleted file mode 100644 index 35037cb28..000000000 --- a/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2020 Moritz Zwerger - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.modding.event; - -import de.bixilon.minosoft.modding.event.events.Event; -import de.bixilon.minosoft.modding.loading.Priorities; - -public class CallbackEventInvoker extends EventInvoker { - private final InvokerCallback callback; - - public CallbackEventInvoker(boolean ignoreCancelled, InvokerCallback callback) { - super(ignoreCancelled, Priorities.NORMAL, null); - this.callback = callback; - } - - // if you need instant fireing support - public CallbackEventInvoker(InvokerCallback callback) { - this(false, callback); - } - - @SuppressWarnings("unchecked") - public void invoke(Event event) { - try { - this.callback.handle((V) event); - } catch (ClassCastException ignored) { - } - } - - public Class getEventType() { - return Event.class; - } - - public interface InvokerCallback { - void handle(V event); - } -} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.kt b/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.kt new file mode 100644 index 000000000..36da90866 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/CallbackEventInvoker.kt @@ -0,0 +1,43 @@ +/* + * Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.modding.event + +import de.bixilon.minosoft.modding.event.events.Event +import de.bixilon.minosoft.modding.loading.Priorities + +class CallbackEventInvoker private constructor( + ignoreCancelled: Boolean, + private val callback: (event: E) -> Unit, + private val eventType: Class, +) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null) { + + override fun invoke(event: Event) { + callback.invoke(event as E) + } + + override fun getEventType(): Class { + return eventType + } + + companion object { + @JvmOverloads + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + inline fun of(ignoreCancelled: Boolean = false, noinline callback: (event: E) -> Unit): CallbackEventInvoker { + return CallbackEventInvoker( + ignoreCancelled = ignoreCancelled, + callback = callback, + eventType = E::class.java + ) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt index 5d180ce2e..867f28775 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt @@ -56,6 +56,9 @@ abstract class Connection { } for (eventInvoker in eventListeners) { + if (!eventInvoker.eventType.isAssignableFrom(connectionEvent::class.java)) { + continue + } eventInvoker.invoke(connectionEvent) } if (connectionEvent is CancelableEvent) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/StatusConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/StatusConnection.kt index e0bc2d1e3..9f8c1ab54 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/StatusConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/StatusConnection.kt @@ -149,10 +149,11 @@ class StatusConnection( } override fun registerEvent(method: EventInvoker) { - if (method.eventType.isAssignableFrom(ServerListStatusArriveEvent::class.java) && wasPingDone()) { + val wasPingDone = wasPingDone() + if (method.eventType.isAssignableFrom(ServerListStatusArriveEvent::class.java) && wasPingDone) { // ping done method.invoke(ServerListStatusArriveEvent(this, this.lastPing)) - } else if (method.eventType.isAssignableFrom(ServerListPongEvent::class.java) && wasPingDone() && this.pong != null) { + } else if (method.eventType.isAssignableFrom(ServerListPongEvent::class.java) && wasPingDone && this.pong != null) { method.invoke(this.pong) } else { super.registerEvent(method)