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.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<Integer, Version> 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!");
}
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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<String, Mappings> mappingSet : mappingsHashMap.entrySet()) {

View File

@ -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);

View File

@ -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;
}

View File

@ -111,6 +111,7 @@ public class ServerListCell extends ListCell<Server> 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<Server> 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) {

View File

@ -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() {

View File

@ -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<? extends ClientboundPacket> 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<? 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();
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.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;
}

View File

@ -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) {

View File

@ -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();