auto load mappings after pong arrived (or version was specified), refactor networking a bit (no sleep anymore)

This commit is contained in:
Bixilon 2020-08-30 23:27:39 +02:00
parent 9c4b7cd991
commit 7f46603ef0
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
12 changed files with 102 additions and 103 deletions

View File

@ -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.GUITools;
import de.bixilon.minosoft.gui.main.Server; import de.bixilon.minosoft.gui.main.Server;
import de.bixilon.minosoft.gui.main.ServerListCell; import de.bixilon.minosoft.gui.main.ServerListCell;
import de.bixilon.minosoft.logging.Log;
import javafx.application.Application; import javafx.application.Application;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -41,6 +42,7 @@ public class Launcher extends Application {
@Override @Override
public void start(Stage primaryStage) throws IOException { public void start(Stage primaryStage) throws IOException {
Log.info("Starting launcher...");
GUITools.versions.add(Versions.getLowestVersionSupported()); GUITools.versions.add(Versions.getLowestVersionSupported());
for (Map.Entry<Integer, Version> version : Versions.getVersionMap().entrySet()) { for (Map.Entry<Integer, Version> version : Versions.getVersionMap().entrySet()) {
GUITools.versions.add(version.getValue()); GUITools.versions.add(version.getValue());
@ -83,5 +85,6 @@ public class Launcher extends Application {
primaryStage.show(); primaryStage.show();
primaryStage.setOnCloseRequest(windowEvent -> System.exit(0)); primaryStage.setOnCloseRequest(windowEvent -> System.exit(0));
Log.info("Launcher started!");
} }
} }

View File

@ -65,6 +65,7 @@ public class Minosoft {
} }
Log.info(String.format("Loaded versions mapping in %dms", (System.currentTimeMillis() - mappingStartLoadingTime))); Log.info(String.format("Loaded versions mapping in %dms", (System.currentTimeMillis() - mappingStartLoadingTime)));
Log.debug("Refreshing token...");
checkClientToken(); checkClientToken();
accountList = config.getMojangAccounts(); accountList = config.getMojangAccounts();
@ -82,6 +83,7 @@ public class Minosoft {
} else { } else {
Log.mojang("Could not refresh session, you will not be able to join premium servers!"); Log.mojang("Could not refresh session, you will not be able to join premium servers!");
} }
Log.debug("Refreshed token!");
serverList = config.getServers(); serverList = config.getServers();
Launcher.main(); Launcher.main();

View File

@ -109,7 +109,6 @@ public class Configuration {
String basePath = String.format("servers.%d.", server.getId()); String basePath = String.format("servers.%d.", server.getId());
putString(basePath + "name", server.getName()); putString(basePath + "name", server.getName());
putString(basePath + "address", server.getAddress()); putString(basePath + "address", server.getAddress());
putString(basePath + "account", server.getAccount());
putInt(basePath + "version", server.getDesiredVersion()); putInt(basePath + "version", server.getDesiredVersion());
if (server.getBase64Favicon() != null) { if (server.getBase64Favicon() != null) {
putString(basePath + "favicon", server.getBase64Favicon()); putString(basePath + "favicon", server.getBase64Favicon());
@ -208,7 +207,7 @@ public class Configuration {
if (entry.containsKey("favicon")) { if (entry.containsKey("favicon")) {
favicon = (String) entry.get("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; return servers;
} }

View File

@ -126,6 +126,10 @@ public class Versions {
} else { } else {
version = versionMap.get(protocolId); version = versionMap.get(protocolId);
} }
if (version.getMapping() != null && version.getMapping().isFullyLoaded()) {
// already loaded
return;
}
Log.verbose(String.format("Loading mappings for version %s...", version)); Log.verbose(String.format("Loading mappings for version %s...", version));
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
for (Map.Entry<String, Mappings> mappingSet : mappingsHashMap.entrySet()) { for (Map.Entry<String, Mappings> mappingSet : mappingsHashMap.entrySet()) {

View File

@ -55,6 +55,7 @@ public class MainWindow implements Initializable {
TextField serverName = new TextField(); TextField serverName = new TextField();
serverName.setPromptText("Servername"); serverName.setPromptText("Servername");
serverName.setText("A Minosoft server");
TextField serverAddress = new TextField(); TextField serverAddress = new TextField();
serverAddress.setPromptText("Server address"); serverAddress.setPromptText("Server address");
@ -78,7 +79,7 @@ public class MainWindow implements Initializable {
dialog.setResultConverter(dialogButton -> { dialog.setResultConverter(dialogButton -> {
if (dialogButton == loginButtonType) { 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); Minosoft.serverList.add(server);
server.saveToConfig(); server.saveToConfig();
ServerListCell.listView.getItems().add(server); ServerListCell.listView.getItems().add(server);

View File

@ -23,23 +23,20 @@ public class Server {
final int id; final int id;
String name; String name;
String address; String address;
String account;
int desiredVersion; int desiredVersion;
String favicon; 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.id = id;
this.name = name; this.name = name;
this.address = address; this.address = address;
this.account = account;
this.desiredVersion = desiredVersion; 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.id = id;
this.name = name; this.name = name;
this.address = address; this.address = address;
this.account = account;
this.desiredVersion = desiredVersion; this.desiredVersion = desiredVersion;
this.favicon = favicon; this.favicon = favicon;
} }
@ -60,14 +57,6 @@ public class Server {
this.address = address; this.address = address;
} }
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public int getDesiredVersion() { public int getDesiredVersion() {
return desiredVersion; return desiredVersion;
} }

View File

@ -111,6 +111,7 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
players.setText(""); players.setText("");
version.setText("Offline"); version.setText("Offline");
motd.setText("Could not connect to server!"); motd.setText("Could not connect to server!");
motd.setTextFill(Color.RED);
optionsConnect.setDisable(true); optionsConnect.setDisable(true);
canConnect = false; canConnect = false;
return; return;
@ -138,7 +139,7 @@ public class ServerListCell extends ListCell<Server> implements Initializable {
icon.setImage(ping.getFavicon()); 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 -> { setOnMouseClicked(click -> {
if (click.getClickCount() == 2) { if (click.getClickCount() == 2) {

View File

@ -71,19 +71,13 @@ public class Connection {
this.hostname = hostname; 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) { public void resolve(ConnectionReasons reason, int protocolId) {
this.desiredVersionNumber = protocolId; this.desiredVersionNumber = protocolId;
Thread resolveThread = new Thread(() -> { Thread resolveThread = new Thread(() -> {
if (desiredVersionNumber != -1) {
setVersion(Versions.getVersionById(desiredVersionNumber));
}
if (addresses == null) { if (addresses == null) {
try { try {
addresses = DNSUtil.getServerAddresses(hostname); addresses = DNSUtil.getServerAddresses(hostname);
@ -113,10 +107,7 @@ public class Connection {
network.connect(address); network.connect(address);
} }
/** private void connect() {
* Tries to connect to the server and login
*/
public void connect() {
Log.info(String.format("Connecting to server: %s", address)); Log.info(String.format("Connecting to server: %s", address));
if (reason == null || reason == ConnectionReasons.DNS) { if (reason == null || reason == ConnectionReasons.DNS) {
// first get version, then login // first get version, then login
@ -205,7 +196,6 @@ public class Connection {
public void setVersion(Version version) { public void setVersion(Version version) {
this.version = version; this.version = version;
this.customMapping.setVersion(version); this.customMapping.setVersion(version);
if (reason == ConnectionReasons.GET_VERSION) {
try { try {
Versions.loadVersionMappings(version.getProtocolVersion()); Versions.loadVersionMappings(version.getProtocolVersion());
} catch (Exception e) { } catch (Exception e) {
@ -214,7 +204,6 @@ public class Connection {
System.exit(1); System.exit(1);
} }
customMapping.setVersion(version); customMapping.setVersion(version);
}
} }
public PacketHandler getHandler() { public PacketHandler getHandler() {

View File

@ -64,6 +64,8 @@ public class Network {
socket = new Socket(); socket = new Socket();
socket.setSoTimeout(ProtocolDefinition.SOCKET_CONNECT_TIMEOUT); socket.setSoTimeout(ProtocolDefinition.SOCKET_CONNECT_TIMEOUT);
socket.connect(new InetSocketAddress(address.getHostname(), address.getPort()), 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; connected = true;
connection.setConnectionState(ConnectionStates.HANDSHAKING); connection.setConnectionState(ConnectionStates.HANDSHAKING);
socket.setKeepAlive(true); socket.setKeepAlive(true);
@ -120,79 +122,82 @@ public class Network {
} }
} }
// everything sent for now, waiting for data // everything sent for now, waiting for data
if (inputStream.available() > 0) { // available seems not to work in CipherInputStream int numRead = 0;
int numRead = 0; int length = 0;
int length = 0; int read;
byte read; do {
do { read = cipherInputStream.read();
read = cipherInputStream.readNBytes(1)[0]; if (read == -1) {
int value = (read & 0b01111111); break;
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();
}
} }
int value = (read & 0b01111111);
length |= (value << (7 * numRead));
InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection); numRead++;
Packets.Clientbound packet = null; if (numRead > 5) {
try { throw new RuntimeException("VarInt is too big");
packet = connection.getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand()); }
if (packet == null) { } while ((read & 0b10000000) != 0);
Log.fatal(String.format("Version packet enum does not contain a packet with id 0x%x. Your version.json is broken!", inPacketBuffer.getCommand())); if (length == 0) {
System.exit(1); break;
} }
Class<? extends ClientboundPacket> clazz = packet.getClazz();
if (clazz == null) { byte[] data = cipherInputStream.readNBytes(length);
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 (compressionThreshold >= 0) {
if (packetInstance instanceof PacketLoginSuccess) { // compression is enabled
connection.setConnectionState(ConnectionStates.PLAY); // check if there is a need to decompress it and if so, do it!
} else if (packetInstance instanceof PacketCompressionInterface) { InByteBuffer rawBuffer = new InByteBuffer(data, connection);
compressionThreshold = ((PacketCompressionInterface) packetInstance).getThreshold(); int packetSize = rawBuffer.readVarInt();
} byte[] left = rawBuffer.readBytesLeft();
connection.handle(packetInstance); if (packetSize == 0) {
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { // no need
// safety first, but will not occur data = left;
e.printStackTrace(); } else {
} // need to decompress data
} catch (Exception e) { data = Util.decompress(left, connection).readBytesLeft();
Log.protocol(String.format("An error occurred while parsing an packet (%s): %s", packet, e));
e.printStackTrace();
} }
} }
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<? extends ClientboundPacket> 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(); socket.close();
connected = false; connected = false;

View File

@ -17,6 +17,7 @@ import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.PacketHandler;
import de.bixilon.minosoft.util.Util;
import java.util.UUID; import java.util.UUID;
@ -27,7 +28,7 @@ public class PacketLoginSuccess implements ClientboundPacket {
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
if (buffer.getProtocolId() < 707) { if (buffer.getProtocolId() < 707) {
uuid = UUID.fromString(buffer.readString()); uuid = Util.uuidFromString(buffer.readString());
username = buffer.readString(); username = buffer.readString();
return true; return true;
} }

View File

@ -40,8 +40,13 @@ public final class Util {
} }
} }
public static UUID formatUUID(String uuid) { public static UUID uuidFromString(String uuid) {
return UUID.fromString(UUID_FIX.matcher(uuid.replace("-", "")).replaceAll("$1-$2-$3-$4-$5")); 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) { public static InByteBuffer decompress(byte[] bytes, Connection connection) {

View File

@ -31,7 +31,7 @@ public class MojangAccount {
public MojangAccount(JsonObject json) { public MojangAccount(JsonObject json) {
this.accessToken = json.get("accessToken").getAsString(); this.accessToken = json.get("accessToken").getAsString();
JsonObject profile = json.get("selectedProfile").getAsJsonObject(); 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(); this.playerName = profile.get("name").getAsString();
JsonObject mojang = json.get("user").getAsJsonObject(); JsonObject mojang = json.get("user").getAsJsonObject();