From 7f46603ef0d96e9225ea70c1c7b192fa58920e30 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sun, 30 Aug 2020 23:27:39 +0200 Subject: [PATCH] auto load mappings after pong arrived (or version was specified), refactor networking a bit (no sleep anymore) --- .../java/de/bixilon/minosoft/Launcher.java | 3 + .../java/de/bixilon/minosoft/Minosoft.java | 2 + .../minosoft/config/Configuration.java | 3 +- .../objectLoader/versions/Versions.java | 4 + .../bixilon/minosoft/gui/main/MainWindow.java | 3 +- .../de/bixilon/minosoft/gui/main/Server.java | 15 +- .../minosoft/gui/main/ServerListCell.java | 3 +- .../minosoft/protocol/network/Connection.java | 19 +-- .../minosoft/protocol/network/Network.java | 139 +++++++++--------- .../clientbound/login/PacketLoginSuccess.java | 3 +- .../java/de/bixilon/minosoft/util/Util.java | 9 +- .../util/mojang/api/MojangAccount.java | 2 +- 12 files changed, 102 insertions(+), 103 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/Launcher.java b/src/main/java/de/bixilon/minosoft/Launcher.java index 856c7ae81..069656edd 100644 --- a/src/main/java/de/bixilon/minosoft/Launcher.java +++ b/src/main/java/de/bixilon/minosoft/Launcher.java @@ -18,6 +18,7 @@ import de.bixilon.minosoft.game.datatypes.objectLoader.versions.Versions; import de.bixilon.minosoft.gui.main.GUITools; import de.bixilon.minosoft.gui.main.Server; import de.bixilon.minosoft.gui.main.ServerListCell; +import de.bixilon.minosoft.logging.Log; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -41,6 +42,7 @@ public class Launcher extends Application { @Override public void start(Stage primaryStage) throws IOException { + Log.info("Starting launcher..."); GUITools.versions.add(Versions.getLowestVersionSupported()); for (Map.Entry version : Versions.getVersionMap().entrySet()) { GUITools.versions.add(version.getValue()); @@ -83,5 +85,6 @@ public class Launcher extends Application { primaryStage.show(); primaryStage.setOnCloseRequest(windowEvent -> System.exit(0)); + Log.info("Launcher started!"); } } \ No newline at end of file diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.java b/src/main/java/de/bixilon/minosoft/Minosoft.java index c85a7fa45..d77156383 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.java +++ b/src/main/java/de/bixilon/minosoft/Minosoft.java @@ -65,6 +65,7 @@ public class Minosoft { } Log.info(String.format("Loaded versions mapping in %dms", (System.currentTimeMillis() - mappingStartLoadingTime))); + Log.debug("Refreshing token..."); checkClientToken(); accountList = config.getMojangAccounts(); @@ -82,6 +83,7 @@ public class Minosoft { } else { Log.mojang("Could not refresh session, you will not be able to join premium servers!"); } + Log.debug("Refreshed token!"); serverList = config.getServers(); Launcher.main(); diff --git a/src/main/java/de/bixilon/minosoft/config/Configuration.java b/src/main/java/de/bixilon/minosoft/config/Configuration.java index 2b1415508..ea3ac9e6c 100644 --- a/src/main/java/de/bixilon/minosoft/config/Configuration.java +++ b/src/main/java/de/bixilon/minosoft/config/Configuration.java @@ -109,7 +109,6 @@ public class Configuration { String basePath = String.format("servers.%d.", server.getId()); putString(basePath + "name", server.getName()); putString(basePath + "address", server.getAddress()); - putString(basePath + "account", server.getAccount()); putInt(basePath + "version", server.getDesiredVersion()); if (server.getBase64Favicon() != null) { putString(basePath + "favicon", server.getBase64Favicon()); @@ -208,7 +207,7 @@ public class Configuration { if (entry.containsKey("favicon")) { favicon = (String) entry.get("favicon"); } - servers.add(new Server(Integer.parseInt(set.getKey()), (String) entry.get("name"), (String) entry.get("address"), (String) entry.get("account"), (int) entry.get("version"), favicon)); + servers.add(new Server(Integer.parseInt(set.getKey()), (String) entry.get("name"), (String) entry.get("address"), (int) entry.get("version"), favicon)); } return servers; } diff --git a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java index 71297322f..ac1b2e9e5 100644 --- a/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java +++ b/src/main/java/de/bixilon/minosoft/game/datatypes/objectLoader/versions/Versions.java @@ -126,6 +126,10 @@ public class Versions { } else { version = versionMap.get(protocolId); } + if (version.getMapping() != null && version.getMapping().isFullyLoaded()) { + // already loaded + return; + } Log.verbose(String.format("Loading mappings for version %s...", version)); long startTime = System.currentTimeMillis(); for (Map.Entry mappingSet : mappingsHashMap.entrySet()) { diff --git a/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java index 59d9d5f15..13304e0f2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java @@ -55,6 +55,7 @@ public class MainWindow implements Initializable { TextField serverName = new TextField(); serverName.setPromptText("Servername"); + serverName.setText("A Minosoft server"); TextField serverAddress = new TextField(); serverAddress.setPromptText("Server address"); @@ -78,7 +79,7 @@ public class MainWindow implements Initializable { dialog.setResultConverter(dialogButton -> { if (dialogButton == loginButtonType) { - Server server = new Server(Minosoft.serverList.size() + 1, serverName.getText(), DNSUtil.correctHostName(serverAddress.getText()), null, GUITools.versionList.getSelectionModel().getSelectedItem().getProtocolVersion()); + Server server = new Server(Minosoft.serverList.size() + 1, serverName.getText(), DNSUtil.correctHostName(serverAddress.getText()), GUITools.versionList.getSelectionModel().getSelectedItem().getProtocolVersion()); Minosoft.serverList.add(server); server.saveToConfig(); ServerListCell.listView.getItems().add(server); 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 84f85f515..f48b0078f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/Server.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/Server.java @@ -23,23 +23,20 @@ public class Server { final int id; String name; String address; - String account; int desiredVersion; String favicon; - public Server(int id, String name, String address, String account, int desiredVersion) { + public Server(int id, String name, String address, int desiredVersion) { this.id = id; this.name = name; this.address = address; - this.account = account; this.desiredVersion = desiredVersion; } - public Server(int id, String name, String address, String account, int desiredVersion, String favicon) { + public Server(int id, String name, String address, int desiredVersion, String favicon) { this.id = id; this.name = name; this.address = address; - this.account = account; this.desiredVersion = desiredVersion; this.favicon = favicon; } @@ -60,14 +57,6 @@ public class Server { this.address = address; } - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - public int getDesiredVersion() { return desiredVersion; } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java index 860edacf6..048fc810e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java @@ -111,6 +111,7 @@ public class ServerListCell extends ListCell implements Initializable { players.setText(""); version.setText("Offline"); motd.setText("Could not connect to server!"); + motd.setTextFill(Color.RED); optionsConnect.setDisable(true); canConnect = false; return; @@ -138,7 +139,7 @@ public class ServerListCell extends ListCell implements Initializable { icon.setImage(ping.getFavicon()); } })); - connection.resolve(ConnectionReasons.PING); // resolve dns address and ping + connection.resolve(ConnectionReasons.PING, server.getDesiredVersion()); // resolve dns address and ping } setOnMouseClicked(click -> { if (click.getClickCount() == 2) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java index 313f7e80d..77bd6139a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java @@ -71,19 +71,13 @@ public class Connection { this.hostname = hostname; } - /** - * Sends an server ping to the server (player count, motd, ...) - */ - public void ping() { - Log.info(String.format("Pinging server: %s", address)); - reason = ConnectionReasons.PING; - network.connect(address); - } - public void resolve(ConnectionReasons reason, int protocolId) { this.desiredVersionNumber = protocolId; Thread resolveThread = new Thread(() -> { + if (desiredVersionNumber != -1) { + setVersion(Versions.getVersionById(desiredVersionNumber)); + } if (addresses == null) { try { addresses = DNSUtil.getServerAddresses(hostname); @@ -113,10 +107,7 @@ public class Connection { network.connect(address); } - /** - * Tries to connect to the server and login - */ - public void connect() { + private void connect() { Log.info(String.format("Connecting to server: %s", address)); if (reason == null || reason == ConnectionReasons.DNS) { // first get version, then login @@ -205,7 +196,6 @@ public class Connection { public void setVersion(Version version) { this.version = version; this.customMapping.setVersion(version); - if (reason == ConnectionReasons.GET_VERSION) { try { Versions.loadVersionMappings(version.getProtocolVersion()); } catch (Exception e) { @@ -214,7 +204,6 @@ public class Connection { System.exit(1); } customMapping.setVersion(version); - } } public PacketHandler getHandler() { diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java index 16bf5cf59..3b9e19514 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java @@ -64,6 +64,8 @@ public class Network { socket = new Socket(); socket.setSoTimeout(ProtocolDefinition.SOCKET_CONNECT_TIMEOUT); socket.connect(new InetSocketAddress(address.getHostname(), address.getPort()), ProtocolDefinition.SOCKET_CONNECT_TIMEOUT); + // connected, use minecraft timeout + socket.setSoTimeout(ProtocolDefinition.SOCKET_TIMEOUT); connected = true; connection.setConnectionState(ConnectionStates.HANDSHAKING); socket.setKeepAlive(true); @@ -120,79 +122,82 @@ public class Network { } } -// everything sent for now, waiting for data - if (inputStream.available() > 0) { // available seems not to work in CipherInputStream - int numRead = 0; - int length = 0; - byte read; - do { - read = cipherInputStream.readNBytes(1)[0]; - int value = (read & 0b01111111); - length |= (value << (7 * numRead)); - - numRead++; - if (numRead > 5) { - throw new RuntimeException("VarInt is too big"); - } - } while ((read & 0b10000000) != 0); - - byte[] data = cipherInputStream.readNBytes(length); - - if (compressionThreshold >= 0) { - // compression is enabled - // check if there is a need to decompress it and if so, do it! - InByteBuffer rawBuffer = new InByteBuffer(data, connection); - int packetSize = rawBuffer.readVarInt(); - byte[] left = rawBuffer.readBytesLeft(); - if (packetSize == 0) { - // no need - data = left; - } else { - // need to decompress data - data = Util.decompress(left, connection).readBytesLeft(); - } + // everything sent for now, waiting for data + int numRead = 0; + int length = 0; + int read; + do { + read = cipherInputStream.read(); + if (read == -1) { + break; } + int value = (read & 0b01111111); + length |= (value << (7 * numRead)); - InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection); - Packets.Clientbound packet = null; - try { - packet = connection.getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand()); - if (packet == null) { - Log.fatal(String.format("Version packet enum does not contain a packet with id 0x%x. Your version.json is broken!", inPacketBuffer.getCommand())); - System.exit(1); - } - Class clazz = packet.getClazz(); + numRead++; + if (numRead > 5) { + throw new RuntimeException("VarInt is too big"); + } + } while ((read & 0b10000000) != 0); + if (length == 0) { + break; + } - if (clazz == null) { - Log.warn(String.format("[IN] Received unknown packet (id=0x%x, name=%s, length=%d, dataLength=%d, version=%s, state=%s)", inPacketBuffer.getCommand(), packet, inPacketBuffer.getLength(), inPacketBuffer.getBytesLeft(), connection.getVersion(), connection.getConnectionState())); - continue; - } - try { - ClientboundPacket packetInstance = clazz.getConstructor().newInstance(); - boolean success = packetInstance.read(inPacketBuffer); - if (inPacketBuffer.getBytesLeft() > 0 || !success) { - // warn not all data used - Log.warn(String.format("[IN] Could not parse packet %s (used=%d, available=%d, total=%d, success=%s)", packet, inPacketBuffer.getPosition(), inPacketBuffer.getBytesLeft(), inPacketBuffer.getLength(), success)); - continue; - } + byte[] data = cipherInputStream.readNBytes(length); - //set special settings to avoid miss timing issues - if (packetInstance instanceof PacketLoginSuccess) { - connection.setConnectionState(ConnectionStates.PLAY); - } else if (packetInstance instanceof PacketCompressionInterface) { - compressionThreshold = ((PacketCompressionInterface) packetInstance).getThreshold(); - } - connection.handle(packetInstance); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - // safety first, but will not occur - e.printStackTrace(); - } - } catch (Exception e) { - Log.protocol(String.format("An error occurred while parsing an packet (%s): %s", packet, e)); - e.printStackTrace(); + if (compressionThreshold >= 0) { + // compression is enabled + // check if there is a need to decompress it and if so, do it! + InByteBuffer rawBuffer = new InByteBuffer(data, connection); + int packetSize = rawBuffer.readVarInt(); + byte[] left = rawBuffer.readBytesLeft(); + if (packetSize == 0) { + // no need + data = left; + } else { + // need to decompress data + data = Util.decompress(left, connection).readBytesLeft(); } } - Util.sleep(1); + + InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection); + Packets.Clientbound packet = null; + try { + packet = connection.getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand()); + if (packet == null) { + Log.fatal(String.format("Version packet enum does not contain a packet with id 0x%x. Your version.json is broken!", inPacketBuffer.getCommand())); + System.exit(1); + } + Class clazz = packet.getClazz(); + + if (clazz == null) { + Log.warn(String.format("[IN] Received unknown packet (id=0x%x, name=%s, length=%d, dataLength=%d, version=%s, state=%s)", inPacketBuffer.getCommand(), packet, inPacketBuffer.getLength(), inPacketBuffer.getBytesLeft(), connection.getVersion(), connection.getConnectionState())); + continue; + } + try { + ClientboundPacket packetInstance = clazz.getConstructor().newInstance(); + boolean success = packetInstance.read(inPacketBuffer); + if (inPacketBuffer.getBytesLeft() > 0 || !success) { + // warn not all data used + Log.warn(String.format("[IN] Could not parse packet %s (used=%d, available=%d, total=%d, success=%s)", packet, inPacketBuffer.getPosition(), inPacketBuffer.getBytesLeft(), inPacketBuffer.getLength(), success)); + continue; + } + + //set special settings to avoid miss timing issues + if (packetInstance instanceof PacketLoginSuccess) { + connection.setConnectionState(ConnectionStates.PLAY); + } else if (packetInstance instanceof PacketCompressionInterface) { + compressionThreshold = ((PacketCompressionInterface) packetInstance).getThreshold(); + } + connection.handle(packetInstance); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + // safety first, but will not occur + e.printStackTrace(); + } + } catch (Exception e) { + Log.protocol(String.format("An error occurred while parsing an packet (%s): %s", packet, e)); + e.printStackTrace(); + } } socket.close(); connected = false; diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginSuccess.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginSuccess.java index 1173bac30..a8e1c68c0 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginSuccess.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginSuccess.java @@ -17,6 +17,7 @@ import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.PacketHandler; +import de.bixilon.minosoft.util.Util; import java.util.UUID; @@ -27,7 +28,7 @@ public class PacketLoginSuccess implements ClientboundPacket { @Override public boolean read(InByteBuffer buffer) { if (buffer.getProtocolId() < 707) { - uuid = UUID.fromString(buffer.readString()); + uuid = Util.uuidFromString(buffer.readString()); username = buffer.readString(); return true; } diff --git a/src/main/java/de/bixilon/minosoft/util/Util.java b/src/main/java/de/bixilon/minosoft/util/Util.java index fc38444b7..ffbbf09f7 100644 --- a/src/main/java/de/bixilon/minosoft/util/Util.java +++ b/src/main/java/de/bixilon/minosoft/util/Util.java @@ -40,8 +40,13 @@ public final class Util { } } - public static UUID formatUUID(String uuid) { - return UUID.fromString(UUID_FIX.matcher(uuid.replace("-", "")).replaceAll("$1-$2-$3-$4-$5")); + public static UUID uuidFromString(String uuid) { + if (uuid.length() == 36) { + return UUID.fromString(uuid); + } else if (uuid.length() == 32) { + return UUID.fromString(UUID_FIX.matcher(uuid.replace("-", "")).replaceAll("$1-$2-$3-$4-$5")); + } + throw new IllegalArgumentException(String.format("%s is not a valid UUID String", uuid)); } public static InByteBuffer decompress(byte[] bytes, Connection connection) { diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java b/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java index 7e045528b..dba6e29c7 100644 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java +++ b/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAccount.java @@ -31,7 +31,7 @@ public class MojangAccount { public MojangAccount(JsonObject json) { this.accessToken = json.get("accessToken").getAsString(); JsonObject profile = json.get("selectedProfile").getAsJsonObject(); - this.uuid = Util.formatUUID(profile.get("id").getAsString()); + this.uuid = Util.uuidFromString(profile.get("id").getAsString()); this.playerName = profile.get("name").getAsString(); JsonObject mojang = json.get("user").getAsJsonObject();