mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -04:00
modding: improve code and performance of callback event invoker, convert ServerListCell to kotlin
This commit is contained in:
parent
31904238aa
commit
0d07a308c8
@ -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() {
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<Server> implements Initializable {
|
||||
public static final ListView<Server> 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<ServerListStatusArriveEvent>(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<ServerListPongEvent>(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();
|
||||
}
|
||||
}
|
||||
}
|
358
src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt
Normal file
358
src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.kt
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<Server?>(), 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<ServerListStatusArriveEvent> {
|
||||
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<ServerModInfo>().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<ServerListPongEvent> {
|
||||
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<ConnectionStateChangeEvent> {
|
||||
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<SessionsWindow>(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<Server>()
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): ServerListCell {
|
||||
val loader = FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/server.fxml")))
|
||||
|
||||
loader.load<Any>()
|
||||
return loader.getController()
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<PlayConnection> implements Initializable {
|
||||
public static final ListView<PlayConnection> 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();
|
||||
}
|
||||
}
|
101
src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt
Normal file
101
src/main/java/de/bixilon/minosoft/gui/main/SessionListCell.kt
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<PlayConnection?>(), 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<ConnectionStateChangeEvent> {
|
||||
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<PlayConnection>()
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): SessionListCell? {
|
||||
val loader = FXMLLoader(Minosoft.MINOSOFT_ASSETS_MANAGER.getAssetURL(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "layout/cells/session.fxml")))
|
||||
loader.load<Any>()
|
||||
return loader.getController()
|
||||
}
|
||||
}
|
||||
}
|
@ -129,17 +129,17 @@ class RenderWindow(
|
||||
}
|
||||
|
||||
init {
|
||||
connection.registerEvent(CallbackEventInvoker<ConnectionStateChangeEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<ConnectionStateChangeEvent> {
|
||||
if (it.connection.isDisconnected) {
|
||||
renderQueue.add {
|
||||
glfwSetWindowShouldClose(windowId, true)
|
||||
}
|
||||
}
|
||||
})
|
||||
connection.registerEvent(CallbackEventInvoker<PacketReceiveEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<PacketReceiveEvent> {
|
||||
val packet = it.packet
|
||||
if (packet !is PacketPlayerPositionAndRotation) {
|
||||
return@CallbackEventInvoker
|
||||
return@of
|
||||
}
|
||||
if (latch.count > 0) {
|
||||
latch.countDown()
|
||||
|
@ -127,19 +127,19 @@ class WorldRenderer(
|
||||
prepareWorld(world)
|
||||
}
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker<ChunkUnloadEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<ChunkUnloadEvent> {
|
||||
unloadChunk(it.chunkPosition)
|
||||
})
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker<ChunkDataChangeEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<ChunkDataChangeEvent> {
|
||||
prepareChunk(it.chunkPosition)
|
||||
})
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker<BlockChangeEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<BlockChangeEvent> {
|
||||
prepareChunkSection(it.blockPosition.chunkPosition, it.blockPosition.sectionHeight)
|
||||
})
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker<MultiBlockChangeEvent> {
|
||||
connection.registerEvent(CallbackEventInvoker.of<MultiBlockChangeEvent> {
|
||||
val sectionHeights: MutableSet<Int> = mutableSetOf()
|
||||
for ((key) in it.blocks) {
|
||||
sectionHeights.add(key.sectionHeight)
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<V extends Event> extends EventInvoker {
|
||||
private final InvokerCallback<V> callback;
|
||||
|
||||
public CallbackEventInvoker(boolean ignoreCancelled, InvokerCallback<V> callback) {
|
||||
super(ignoreCancelled, Priorities.NORMAL, null);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
// if you need instant fireing support
|
||||
public CallbackEventInvoker(InvokerCallback<V> callback) {
|
||||
this(false, callback);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void invoke(Event event) {
|
||||
try {
|
||||
this.callback.handle((V) event);
|
||||
} catch (ClassCastException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public Class<? extends Event> getEventType() {
|
||||
return Event.class;
|
||||
}
|
||||
|
||||
public interface InvokerCallback<V> {
|
||||
void handle(V event);
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<E : Event?> private constructor(
|
||||
ignoreCancelled: Boolean,
|
||||
private val callback: (event: E) -> Unit,
|
||||
private val eventType: Class<out Event>,
|
||||
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null) {
|
||||
|
||||
override fun invoke(event: Event) {
|
||||
callback.invoke(event as E)
|
||||
}
|
||||
|
||||
override fun getEventType(): Class<out Event> {
|
||||
return eventType
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmOverloads
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||
inline fun <reified E : Event> of(ignoreCancelled: Boolean = false, noinline callback: (event: E) -> Unit): CallbackEventInvoker<E> {
|
||||
return CallbackEventInvoker(
|
||||
ignoreCancelled = ignoreCancelled,
|
||||
callback = callback,
|
||||
eventType = E::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user