diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/TunnelMC.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/TunnelMC.java index 5c17d59..db48eb7 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/TunnelMC.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/TunnelMC.java @@ -3,7 +3,6 @@ import me.THEREALWWEFAN231.tunnelmc.translator.EntityTranslator; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslatorManager; import me.THEREALWWEFAN231.tunnelmc.translator.blockentity.BlockEntityRegistry; -import me.THEREALWWEFAN231.tunnelmc.translator.blockentity.BlockEntityTranslator; import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.BlockStateTranslator; import me.THEREALWWEFAN231.tunnelmc.translator.container.screenhandler.ScreenHandlerTranslatorManager; import me.THEREALWWEFAN231.tunnelmc.translator.enchantment.EnchantmentTranslator; diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Auth.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Auth.java index 4f578ff..1ed3c77 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Auth.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Auth.java @@ -20,7 +20,10 @@ import me.THEREALWWEFAN231.tunnelmc.TunnelMC; -//based off https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth +/** + * Referenced from the resource below: + * https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth + */ public class Auth { private ECPublicKey publicKey; @@ -30,34 +33,28 @@ public class Auth { private String displayName; public String getOnlineChainData() throws Exception { - Gson gson = TunnelMC.instance.fileManagement.normalGson; + Gson gson = TunnelMC.instance.fileManagement.gJson; - KeyPair ecdsa256KeyPair = Auth.createKeyPair();//for xbox live, xbox live requests use, ES256, ECDSA256 + KeyPair ecdsa256KeyPair = Auth.createKeyPair(); this.publicKey = (ECPublicKey) ecdsa256KeyPair.getPublic(); this.privateKey = (ECPrivateKey) ecdsa256KeyPair.getPrivate(); - - Xbox xbox = new Xbox(System.getProperty("XboxAccessToken")); + + Xbox xbox = new Xbox(System.getenv("XBOX_ACCESS_TOKEN")); String userToken = xbox.getUserToken(this.publicKey, this.privateKey); String deviceToken = xbox.getDeviceToken(this.publicKey, this.privateKey); String titleToken = xbox.getTitleToken(this.publicKey, this.privateKey, deviceToken); String xsts = xbox.getXstsToken(userToken, deviceToken, titleToken, this.publicKey, this.privateKey); - KeyPair ecdsa384KeyPair = EncryptionUtils.createKeyPair();//use ES384, ECDSA384 + KeyPair ecdsa384KeyPair = EncryptionUtils.createKeyPair(); this.publicKey = (ECPublicKey) ecdsa384KeyPair.getPublic(); this.privateKey = (ECPrivateKey) ecdsa384KeyPair.getPrivate(); - /* - * So we get a "chain"(json array with info(that has 2 objects)) from minecraft.net using our xsts token - * from there we have to add our own chain at the beginning of the chain(json array that minecraft.net sent us), - * When is all said and done, we have 3 chains(they are jwt objects, header.payload.signature) - * which we send to the server to check - */ String chainData = xbox.requestMinecraftChain(xsts, this.publicKey); JsonObject chainDataObject = TunnelMC.instance.fileManagement.jsonParser.parse(chainData).getAsJsonObject(); JsonArray minecraftNetChain = chainDataObject.get("chain").getAsJsonArray(); String firstChainHeader = minecraftNetChain.get(0).getAsString(); - firstChainHeader = firstChainHeader.split("\\.")[0];//get the jwt header(base64) - firstChainHeader = new String(Base64.getDecoder().decode(firstChainHeader.getBytes()));//decode the jwt base64 header + firstChainHeader = firstChainHeader.split("\\.")[0]; + firstChainHeader = new String(Base64.getDecoder().decode(firstChainHeader.getBytes())); String firstKeyx5u = TunnelMC.instance.fileManagement.jsonParser.parse(firstChainHeader).getAsJsonObject().get("x5u").getAsString(); JsonObject newFirstChain = new JsonObject(); @@ -66,35 +63,30 @@ public String getOnlineChainData() throws Exception { newFirstChain.addProperty("identityPublicKey", firstKeyx5u); newFirstChain.addProperty("nbf", Instant.now().getEpochSecond() - TimeUnit.HOURS.toSeconds(6)); - { - String publicKeyBase64 = Base64.getEncoder().encodeToString(this.publicKey.getEncoded()); - JsonObject jwtHeader = new JsonObject(); - jwtHeader.addProperty("alg", "ES384"); - jwtHeader.addProperty("x5u", publicKeyBase64); + String publicKeyBase64 = Base64.getEncoder().encodeToString(this.publicKey.getEncoded()); + JsonObject jwtHeader = new JsonObject(); + jwtHeader.addProperty("alg", "ES384"); + jwtHeader.addProperty("x5u", publicKeyBase64); + + String header = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(jwtHeader).getBytes()); + String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(newFirstChain).getBytes()); - String header = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(jwtHeader).getBytes()); - String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(newFirstChain).getBytes()); + byte[] dataToSign = (header + "." + payload).getBytes(); + String signatureString = this.signBytes(dataToSign); - byte[] dataToSign = (header + "." + payload).getBytes(); - String signatureString = this.signBytes(dataToSign); + String jwt = header + "." + payload + "." + signatureString; - String jwt = header + "." + payload + "." + signatureString; + chainDataObject.add("chain", this.addChainToBeginning(jwt, minecraftNetChain)); - chainDataObject.add("chain", this.addChainToBeginning(jwt, minecraftNetChain));//replace the chain with our new chain - } + String lastChain = minecraftNetChain.get(minecraftNetChain.size() - 1).getAsString(); + String lastChainPayload = lastChain.split("\\.")[1]; + lastChainPayload = new String(Base64.getDecoder().decode(lastChainPayload.getBytes())); - { - //we are now going to get some data from a chain minecraft sent us(the last chain) - String lastChain = minecraftNetChain.get(minecraftNetChain.size() - 1).getAsString(); - String lastChainPayload = lastChain.split("\\.")[1];//get the middle(payload) jwt thing - lastChainPayload = new String(Base64.getDecoder().decode(lastChainPayload.getBytes()));//decode the base64 - - JsonObject payloadObject = TunnelMC.instance.fileManagement.jsonParser.parse(lastChainPayload).getAsJsonObject(); - JsonObject extraData = payloadObject.get("extraData").getAsJsonObject(); - this.xuid = extraData.get("XUID").getAsString(); - this.identity = UUID.fromString(extraData.get("identity").getAsString()); - this.displayName = extraData.get("displayName").getAsString(); - } + JsonObject payloadObject = TunnelMC.instance.fileManagement.jsonParser.parse(lastChainPayload).getAsJsonObject(); + JsonObject extraData = payloadObject.get("extraData").getAsJsonObject(); + this.xuid = extraData.get("XUID").getAsString(); + this.identity = UUID.fromString(extraData.get("identity").getAsString()); + this.displayName = extraData.get("displayName").getAsString(); return gson.toJson(chainDataObject); } @@ -105,7 +97,7 @@ public String getOfflineChainData(String username) throws Exception { UUID offlineUUID = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); String xuid = Long.toString(offlineUUID.getLeastSignificantBits()); - Gson gson = TunnelMC.instance.fileManagement.normalGson; + Gson gson = TunnelMC.instance.fileManagement.gJson; //KeyPair ecdsa256KeyPair = Auth.createKeyPair();//for xbox live, xbox live requests use, ES256, ECDSA256 KeyPair ecdsa256KeyPair = EncryptionUtils.createKeyPair(); this.publicKey = (ECPublicKey) ecdsa256KeyPair.getPublic(); @@ -197,7 +189,7 @@ public String getDisplayName() { static { try { KEY_PAIR_GEN = KeyPairGenerator.getInstance("EC"); - KEY_PAIR_GEN.initialize(new ECGenParameterSpec("secp256r1"));//use P-256 + KEY_PAIR_GEN.initialize(new ECGenParameterSpec("secp256r1")); } catch (Exception e) { throw new AssertionError("Unable to initialize required encryption", e); } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/SkinData.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/ClientData.java similarity index 99% rename from src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/SkinData.java rename to src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/ClientData.java index acf9dbf..557dce3 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/SkinData.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/ClientData.java @@ -17,16 +17,16 @@ import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; -public class SkinData { +public class ClientData { //pretty sure this is a base64 of a texture, not 100% sure though, this is the default java steve, THE REAL STEVE private static final String SKIN_DATA_BASE_64 = "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ll9B/5ZfQf+WX0H/lm9b/6p9Zv+Wb1v/lm9b/4dVO/+WX0H/ll9B/5ZfQf+qfWb/lm9b/6p9Zv+Wb1v/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP9WScz/VknM/1ZJzP9WScz/KCgo/ygoKP8oKCj/KCgo/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AKio/wDMzP8AzMz/AKio/1ExJf9qQDD/UTEl/2pAMP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/VknM/1ZJzP9WScz/VknM/ygoKP8oKCj/KCgo/ygoKP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wDMzP8AzMz/AMzM/wDMzP9RMSX/akAw/1ExJf9qQDD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/1ZJzP9WScz/VknM/1ZJzP8oKCj/KCgo/ygoKP8oKCj/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AqKj/AMzM/wDMzP8AzMz/akAw/1ExJf9qQDD/UTEl/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP9WScz/VknM/1ZJzP9WScz/KCgo/ygoKP8oKCj/KCgo/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AKio/wDMzP8AzMz/AKio/2pAMP9RMSX/akAw/1ExJf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8wKHL/MChy/yYhW/8wKHL/Rjql/0Y6pf9GOqX/Rjql/zAocv8mIVv/MChy/zAocv86MYn/Rjql/0Y6pf9GOqX/AH9//wB/f/8Af3//AH9//wCoqP8Ar6//AKio/wCenv8Af3//AH9//wB/f/8Af3//AK+v/wCvr/8Ar6//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"; //i mean if you want to edit this, sure what ever, not sure if it'd work but :shrug: private static final String SKIN_GEOMETRY_DATA = "{\"format_version\":\"1.12.0\",\"minecraft:geometry\":[{\"bones\":[{\"name\":\"body\",\"parent\":\"waist\",\"pivot\":[0,24,0]},{\"name\":\"waist\",\"pivot\":[0,12,0]},{\"cubes\":[{\"origin\":[-5,8,3],\"size\":[10,16,1],\"uv\":[0,0]}],\"name\":\"cape\",\"parent\":\"body\",\"pivot\":[0,24,3],\"rotation\":[0,180,0]}],\"description\":{\"identifier\":\"geometry.cape\",\"texture_height\":32,\"texture_width\":64}},{\"bones\":[{\"name\":\"root\",\"pivot\":[0,0,0]},{\"cubes\":[{\"origin\":[-4,12,-2],\"size\":[8,12,4],\"uv\":[16,16]}],\"name\":\"body\",\"parent\":\"waist\",\"pivot\":[0,24,0]},{\"name\":\"waist\",\"parent\":\"root\",\"pivot\":[0,12,0]},{\"cubes\":[{\"origin\":[-4,24,-4],\"size\":[8,8,8],\"uv\":[0,0]}],\"name\":\"head\",\"parent\":\"body\",\"pivot\":[0,24,0]},{\"name\":\"cape\",\"parent\":\"body\",\"pivot\":[0,24,3]},{\"cubes\":[{\"inflate\":0.5,\"origin\":[-4,24,-4],\"size\":[8,8,8],\"uv\":[32,0]}],\"name\":\"hat\",\"parent\":\"head\",\"pivot\":[0,24,0]},{\"cubes\":[{\"origin\":[4,12,-2],\"size\":[4,12,4],\"uv\":[32,48]}],\"name\":\"leftArm\",\"parent\":\"body\",\"pivot\":[5,22,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[4,12,-2],\"size\":[4,12,4],\"uv\":[48,48]}],\"name\":\"leftSleeve\",\"parent\":\"leftArm\",\"pivot\":[5,22,0]},{\"name\":\"leftItem\",\"parent\":\"leftArm\",\"pivot\":[6,15,1]},{\"cubes\":[{\"origin\":[-8,12,-2],\"size\":[4,12,4],\"uv\":[40,16]}],\"name\":\"rightArm\",\"parent\":\"body\",\"pivot\":[-5,22,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-8,12,-2],\"size\":[4,12,4],\"uv\":[40,32]}],\"name\":\"rightSleeve\",\"parent\":\"rightArm\",\"pivot\":[-5,22,0]},{\"locators\":{\"lead_hold\":[-6,15,1]},\"name\":\"rightItem\",\"parent\":\"rightArm\",\"pivot\":[-6,15,1]},{\"cubes\":[{\"origin\":[-0.1,0,-2],\"size\":[4,12,4],\"uv\":[16,48]}],\"name\":\"leftLeg\",\"parent\":\"root\",\"pivot\":[1.9,12,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-0.1,0,-2],\"size\":[4,12,4],\"uv\":[0,48]}],\"name\":\"leftPants\",\"parent\":\"leftLeg\",\"pivot\":[1.9,12,0]},{\"cubes\":[{\"origin\":[-3.9,0,-2],\"size\":[4,12,4],\"uv\":[0,16]}],\"name\":\"rightLeg\",\"parent\":\"root\",\"pivot\":[-1.9,12,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-3.9,0,-2],\"size\":[4,12,4],\"uv\":[0,32]}],\"name\":\"rightPants\",\"parent\":\"rightLeg\",\"pivot\":[-1.9,12,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-4,12,-2],\"size\":[8,12,4],\"uv\":[16,32]}],\"name\":\"jacket\",\"parent\":\"body\",\"pivot\":[0,24,0]}],\"description\":{\"identifier\":\"geometry.humanoid.custom\",\"texture_height\":64,\"texture_width\":64,\"visible_bounds_height\":2,\"visible_bounds_offset\":[0,1,0],\"visible_bounds_width\":1}},{\"bones\":[{\"name\":\"root\",\"pivot\":[0,0,0]},{\"name\":\"waist\",\"parent\":\"root\",\"pivot\":[0,12,0]},{\"cubes\":[{\"origin\":[-4,12,-2],\"size\":[8,12,4],\"uv\":[16,16]}],\"name\":\"body\",\"parent\":\"waist\",\"pivot\":[0,24,0]},{\"cubes\":[{\"origin\":[-4,24,-4],\"size\":[8,8,8],\"uv\":[0,0]}],\"name\":\"head\",\"parent\":\"body\",\"pivot\":[0,24,0]},{\"cubes\":[{\"inflate\":0.5,\"origin\":[-4,24,-4],\"size\":[8,8,8],\"uv\":[32,0]}],\"name\":\"hat\",\"parent\":\"head\",\"pivot\":[0,24,0]},{\"cubes\":[{\"origin\":[-3.9,0,-2],\"size\":[4,12,4],\"uv\":[0,16]}],\"name\":\"rightLeg\",\"parent\":\"root\",\"pivot\":[-1.9,12,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-3.9,0,-2],\"size\":[4,12,4],\"uv\":[0,32]}],\"name\":\"rightPants\",\"parent\":\"rightLeg\",\"pivot\":[-1.9,12,0]},{\"cubes\":[{\"origin\":[-0.1,0,-2],\"size\":[4,12,4],\"uv\":[16,48]}],\"mirror\":true,\"name\":\"leftLeg\",\"parent\":\"root\",\"pivot\":[1.9,12,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-0.1,0,-2],\"size\":[4,12,4],\"uv\":[0,48]}],\"name\":\"leftPants\",\"parent\":\"leftLeg\",\"pivot\":[1.9,12,0]},{\"cubes\":[{\"origin\":[4,11.5,-2],\"size\":[3,12,4],\"uv\":[32,48]}],\"name\":\"leftArm\",\"parent\":\"body\",\"pivot\":[5,21.5,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[4,11.5,-2],\"size\":[3,12,4],\"uv\":[48,48]}],\"name\":\"leftSleeve\",\"parent\":\"leftArm\",\"pivot\":[5,21.5,0]},{\"name\":\"leftItem\",\"parent\":\"leftArm\",\"pivot\":[6,14.5,1]},{\"cubes\":[{\"origin\":[-7,11.5,-2],\"size\":[3,12,4],\"uv\":[40,16]}],\"name\":\"rightArm\",\"parent\":\"body\",\"pivot\":[-5,21.5,0]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-7,11.5,-2],\"size\":[3,12,4],\"uv\":[40,32]}],\"name\":\"rightSleeve\",\"parent\":\"rightArm\",\"pivot\":[-5,21.5,0]},{\"locators\":{\"lead_hold\":[-6,14.5,1]},\"name\":\"rightItem\",\"parent\":\"rightArm\",\"pivot\":[-6,14.5,1]},{\"cubes\":[{\"inflate\":0.25,\"origin\":[-4,12,-2],\"size\":[8,12,4],\"uv\":[16,32]}],\"name\":\"jacket\",\"parent\":\"body\",\"pivot\":[0,24,0]},{\"name\":\"cape\",\"parent\":\"body\",\"pivot\":[0,24,-3]}],\"description\":{\"identifier\":\"geometry.humanoid.customSlim\",\"texture_height\":64,\"texture_width\":64,\"visible_bounds_height\":2,\"visible_bounds_offset\":[0,1,0],\"visible_bounds_width\":1}}]}"; - public static String getSkinData(String serverAddress) { + public static String getClientData(String serverAddress) { try { - Gson gson = TunnelMC.instance.fileManagement.normalGson; + Gson gson = TunnelMC.instance.fileManagement.gJson; String publicKeyBase64 = Base64.getEncoder().encodeToString(Client.instance.authData.getPublicKey().getEncoded()); @@ -63,8 +63,8 @@ public static String getSkinData(String serverAddress) { skinData.addProperty("ServerAddress", serverAddress); skinData.addProperty("SkinAnimationData", ""); skinData.addProperty("SkinColor", "#0"); - skinData.addProperty("SkinData", SkinData.SKIN_DATA_BASE_64); - skinData.addProperty("SkinGeometryData", Base64.getEncoder().encodeToString(SkinData.SKIN_GEOMETRY_DATA.getBytes())); + skinData.addProperty("SkinData", ClientData.SKIN_DATA_BASE_64); + skinData.addProperty("SkinGeometryData", Base64.getEncoder().encodeToString(ClientData.SKIN_GEOMETRY_DATA.getBytes())); skinData.addProperty("SkinId", UUID.randomUUID() + ".Custom" + UUID.randomUUID());//ok..? :shrug: skinData.addProperty("SkinImageHeight", 64); skinData.addProperty("SkinImageWidth", 64); @@ -86,7 +86,6 @@ public static String getSkinData(String serverAddress) { return null; } - //this is just a simple way... @SuppressWarnings("unused") private static String skinTextureToString(File file) throws Exception { BufferedImage bufferedImage = ImageIO.read(file); diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Xbox.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Xbox.java index 7e6f830..5e02e1b 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Xbox.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/auth/Xbox.java @@ -21,18 +21,20 @@ import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; -/* - * This note refers to all auth/JWT related classes, I know there are JWT parsing dependencies(already built into the protocol - * dependence) but I want to to be "up front", meaning I/we see everything that is going on, meaning we can see exactly how - * the header, payload and signature are formed, rather then using some library that make take a couple minutes to understand(how - * it works), I also do know, at some points it would be easier to use the JWT dependence but my stance above still applies, - * maybe ill make my own simple class :shrug: +/** + * Referenced from the resource below: + * https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth */ -//based off https://github.com/Sandertv/gophertunnel/tree/master/minecraft/auth public class Xbox { - //go here, log in, and in the redirected url you will have your access token, https://login.live.com/oauth20_authorize.srf?client_id=00000000441cc96b&redirect_uri=https://login.live.com/oauth20_desktop.srf&response_type=token&display=touch&scope=service::user.auth.xboxlive.com::MBI_SSL&locale=en - //then add -DXboxAccessToken=YOURS to your jvm arguments + /** + * To generate your own access token (for now), login at the following link: + * https://login.live.com/oauth20_authorize.srf?client_id=00000000441cc96b&redirect_uri=https://login.live.com/oauth20_desktop.srf&response_type=token&display=touch&scope=service::user.auth.xboxlive.com::MBI_SSL&locale=en + * When you're redirected to the blank page, check the URL parameters. Look for the one that says access token, and then set + * the "XBOX_ACCESS_TOKEN" environment variable to your access token. + * + * This will be changed and simplified later on. + */ private final String accessToken; private static final String xboxUserAuthURL = "https://user.auth.xboxlive.com/user/authenticate"; @@ -48,7 +50,6 @@ public Xbox(String accessToken) { } public String getUserToken(ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception { - JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com"); jsonObject.addProperty("TokenType", "JWT"); @@ -85,7 +86,6 @@ public String getUserToken(ECPublicKey publicKey, ECPrivateKey privateKey) throw } public String getDeviceToken(ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception { - JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com"); jsonObject.addProperty("TokenType", "JWT"); @@ -124,7 +124,6 @@ public String getDeviceToken(ECPublicKey publicKey, ECPrivateKey privateKey) thr } public String getTitleToken(ECPublicKey publicKey, ECPrivateKey privateKey, String deviceToken) throws Exception { - JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("RelyingParty", "http://auth.xboxlive.com"); jsonObject.addProperty("TokenType", "JWT"); @@ -162,7 +161,6 @@ public String getTitleToken(ECPublicKey publicKey, ECPrivateKey privateKey, Stri } public String getXstsToken(String userToken, String deviceToken, String titleToken, ECPublicKey publicKey, ECPrivateKey privateKey) throws Exception { - JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("RelyingParty", "https://multiplayer.minecraft.net/"); @@ -227,7 +225,7 @@ private void writeJsonObjectToPost(HttpsURLConnection connection, JsonObject jso connection.setDoOutput(true); DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream()); - dataOutputStream.writeBytes(TunnelMC.instance.fileManagement.normalGson.toJson(jsonObject)); + dataOutputStream.writeBytes(TunnelMC.instance.fileManagement.gJson.toJson(jsonObject)); dataOutputStream.flush(); } @@ -261,7 +259,7 @@ private void addSignatureHeader(HttpsURLConnection httpsURLConnection, JsonObjec } bytesToSign.write(authorization.getBytes()); bytesToSign.write(new byte[] { 0 }); - bytesToSign.write(TunnelMC.instance.fileManagement.normalGson.toJson(postData).getBytes()); + bytesToSign.write(TunnelMC.instance.fileManagement.gJson.toJson(postData).getBytes()); bytesToSign.write(new byte[] { 0 }); Signature signature = Signature.getInstance("SHA256withECDSA"); diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/bedrockconnection/Client.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/bedrockconnection/Client.java index 64920be..9e0ac93 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/bedrockconnection/Client.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/bedrockconnection/Client.java @@ -1,46 +1,59 @@ package me.THEREALWWEFAN231.tunnelmc.bedrockconnection; -import java.net.InetSocketAddress; -import java.util.function.BiConsumer; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - +import com.nukkitx.network.util.DisconnectReason; import com.nukkitx.protocol.bedrock.BedrockClient; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockSession; +import com.nukkitx.protocol.bedrock.data.GameType; import com.nukkitx.protocol.bedrock.packet.LoginPacket; import com.nukkitx.protocol.bedrock.v431.Bedrock_v431; - import io.netty.util.AsciiString; import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.auth.Auth; -import me.THEREALWWEFAN231.tunnelmc.auth.SkinData; +import me.THEREALWWEFAN231.tunnelmc.auth.ClientData; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.caches.BlockEntityDataCache; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.caches.container.BedrockContainers; +import me.THEREALWWEFAN231.tunnelmc.gui.BedrockConnectingScreen; import me.THEREALWWEFAN231.tunnelmc.javaconnection.FakeJavaConnection; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.DisconnectedScreen; -import net.minecraft.client.util.NetworkUtils; +import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.text.Text; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.util.function.BiConsumer; public class Client { public static Client instance = new Client(); - private final Logger logger = LogManager.getLogger(ClientBatchHandler.class); + public BedrockPacketCodec bedrockPacketCodec = Bedrock_v431.V431_CODEC; + private final Logger logger = LogManager.getLogger(ClientBatchHandler.class); + private String ip; private int port; + + public GameType defaultGameMode; private boolean onlineMode; + public Auth authData; + public BedrockClient bedrockClient; + public BedrockConnectingScreen connectScreen; + public FakeJavaConnection javaConnection; public BedrockContainers containers; public BlockEntityDataCache blockEntityDataCache; - public byte openContainerId; + + public int entityRuntimeId; + public byte openContainerId = 0; public void initialize(String ip, int port, boolean onlineMode) { this.ip = ip; @@ -50,25 +63,56 @@ public void initialize(String ip, int port, boolean onlineMode) { org.apache.logging.log4j.core.Logger logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger(); logger.get().setLevel(Level.DEBUG); - InetSocketAddress bindAddress = new InetSocketAddress("0.0.0.0", this.getOpenLocalPort()); + InetSocketAddress bindAddress = new InetSocketAddress("0.0.0.0", getRandomPort()); this.bedrockClient = new BedrockClient(bindAddress); this.bedrockClient.bind().join(); + this.connectScreen = new BedrockConnectingScreen(MinecraftClient.getInstance().currentScreen, MinecraftClient.getInstance(), this.bedrockClient); + TunnelMC.mc.openScreen(this.connectScreen); InetSocketAddress addressToConnect = new InetSocketAddress(ip, port); this.bedrockClient.connect(addressToConnect).whenComplete((BiConsumer) (session, throwable) -> { if (throwable != null) { - MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect(new DisconnectedScreen(MinecraftClient.getInstance().currentScreen, Text.of("Use Translated Here"), Text.of(throwable.getMessage())))); + MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect( + new DisconnectedScreen( + new TitleScreen(false), + Text.of("TunnelMC"), + Text.of(throwable.getMessage()) + ) + )); return; } + this.connectScreen.setStatus(Text.of("Logging in...")); Client.this.onSessionInitialized(session); }); } + private int getRandomPort() { + try (DatagramSocket datagramSocket = new DatagramSocket(0)) { + return datagramSocket.getLocalPort(); + } catch(SocketException e) { + throw new RuntimeException("Could not open socket to find next free port", e); + } + } + public void onSessionInitialized(BedrockSession bedrockSession) { bedrockSession.setPacketCodec(this.bedrockPacketCodec); - bedrockSession.addDisconnectHandler(reason -> System.out.println("Disconnected")); + bedrockSession.addDisconnectHandler(reason -> MinecraftClient.getInstance().execute(() -> { + // We disconnected ourselves. + if (reason == DisconnectReason.DISCONNECTED) { + return; + } + + MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect( + new DisconnectedScreen( + new TitleScreen(false), + Text.of("TunnelMC"), + Text.of("You were disconnected from the target server because: " + reason.toString()) + ) + )); + })); + bedrockSession.setBatchHandler(new ClientBatchHandler()); bedrockSession.setLogging(false); @@ -83,24 +127,40 @@ public void onSessionInitialized(BedrockSession bedrockSession) { chainData = this.authData.getOfflineChainData(TunnelMC.mc.getSession().getUsername()); } + String clientData = ClientData.getClientData(this.ip + ":" + this.port); + if (clientData == null) { + MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect( + new DisconnectedScreen( + new TitleScreen(false), + Text.of("TunnelMC"), + Text.of("There was an error when generating client data. Please try again later.") + ) + )); + return; + } + loginPacket.setProtocolVersion(bedrockSession.getPacketCodec().getProtocolVersion()); loginPacket.setChainData(new AsciiString(chainData.getBytes())); - loginPacket.setSkinData(new AsciiString(SkinData.getSkinData(this.ip + ":" + this.port))); + loginPacket.setSkinData(new AsciiString(clientData)); this.sendPacketImmediately(loginPacket); - this.javaConnection = new FakeJavaConnection(); + this.connectScreen.setStatus(Text.of("Loading resources...")); + this.javaConnection = new FakeJavaConnection(); } catch (Exception e) { - //TODO: do something better with this - e.printStackTrace(); + MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect( + new DisconnectedScreen( + new TitleScreen(false), + Text.of("TunnelMC"), + Text.of(e.getMessage()) + ) + )); } } - - //when our java player is initialized + public void onPlayerInitialized() { this.containers = new BedrockContainers(); this.blockEntityDataCache = new BlockEntityDataCache(); - this.openContainerId = 0; } public boolean isConnectionOpen() { @@ -119,19 +179,12 @@ public void sendPacketImmediately(BedrockPacket packet) { public void sendPacket(BedrockPacket packet) { BedrockSession session = this.bedrockClient.getSession(); - session.sendPacket(packet); - if (session.isLogging()) { - this.logger.info("Outbound {}: {}", session.getAddress().toString(), packet.getClass().getCanonicalName()); - } - } - - public int getOpenLocalPort() { - int port = NetworkUtils.findLocalPort();//minecraft does this when opening world to lan - if (port == 25564) {//fallback port, we are going to change it because we are cool - port = 2021; + if (session != null) { + session.sendPacket(packet); + if (session.isLogging()) { + this.logger.info("Outbound {}: {}", session.getAddress().toString(), packet.getClass().getCanonicalName()); + } } - return port; - // return 12345; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectingScreen.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectingScreen.java new file mode 100644 index 0000000..884aab5 --- /dev/null +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectingScreen.java @@ -0,0 +1,65 @@ +package me.THEREALWWEFAN231.tunnelmc.gui; + +import com.nukkitx.protocol.bedrock.BedrockClient; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ScreenTexts; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.NarratorManager; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Util; + +@Environment(EnvType.CLIENT) +public class BedrockConnectingScreen extends Screen { + + private Text status = new TranslatableText("connect.connecting"); + private long narratorTimer = -1L; + private final BedrockClient connection; + private final Screen parent; + + public BedrockConnectingScreen(Screen parent, MinecraftClient client, BedrockClient connection) { + super(NarratorManager.EMPTY); + this.client = client; + this.parent = parent; + this.connection = connection; + } + + public void setStatus(Text status) { + this.status = status; + } + + public boolean shouldCloseOnEsc() { + return false; + } + + protected void init() { + if (this.client == null) { + return; + } + + this.addButton(new ButtonWidget(this.width / 2 - 100, this.height / 4 + 120 + 12, 200, 20, ScreenTexts.CANCEL, (buttonWidget) -> { + if (this.connection != null) { + this.connection.close(true); + } + + this.client.openScreen(this.parent); + })); + } + + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + this.renderBackground(matrices); + long l = Util.getMeasuringTimeMs(); + if (l - this.narratorTimer > 2000L) { + this.narratorTimer = l; + NarratorManager.INSTANCE.narrate((new TranslatableText("narrator.joining")).getString()); + } + + drawCenteredText(matrices, this.textRenderer, this.status, this.width / 2, this.height / 2 - 50, 16777215); + super.render(matrices, mouseX, mouseY, delta); + } + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectionScreen.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectionScreen.java index cf58ec2..eb5dde1 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectionScreen.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/gui/BedrockConnectionScreen.java @@ -32,6 +32,9 @@ public BedrockConnectionScreen(Screen parent) { } public void init() { + if (this.client == null) { + return; + } this.client.keyboard.setRepeatEvents(true); this.joinServerButton = this.addButton(new ButtonWidget(this.width / 2 - 102, this.height / 4 + 100 + 12, 204, 20, new TranslatableText("selectServer.select"), button -> { if (BedrockConnectionScreen.this.addressField.getText().isEmpty()) { diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClickSlotC2SPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClickSlotC2SPacketTranslator.java index 909dcbb..7f27397 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClickSlotC2SPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClickSlotC2SPacketTranslator.java @@ -18,6 +18,8 @@ public class ClickSlotC2SPacketTranslator extends PacketTranslator { + // TODO: Re-review this code and clean it up later on, seems incorrect. + @Override public void translate(ClickSlotC2SPacket packet) { @@ -28,50 +30,45 @@ public Class getPacketClass() { return ClickSlotC2SPacket.class; } - //MixinScreenHandler public void onCursorStackClickEmptySlot(ScreenHandler screenHandler, int clickedSlotId, int itemCountToMoveFromCursorToClickedSlot) { + if (TunnelMC.mc.player == null) { + return; + } InventoryTransactionPacket inventoryTransactionPacket = new InventoryTransactionPacket(); inventoryTransactionPacket.setTransactionType(TransactionType.NORMAL); - inventoryTransactionPacket.setActionType(0);//I have no idea + inventoryTransactionPacket.setActionType(0); inventoryTransactionPacket.setRuntimeEntityId(TunnelMC.mc.player.getEntityId()); - { - BedrockContainer cursorContainer = Client.instance.containers.getPlayerContainerCursorContainer(); - BedrockContainer containerForClickedSlot = ScreenHandlerTranslatorManager.getBedrockContainerFromJava(screenHandler, clickedSlotId); + BedrockContainer cursorContainer = Client.instance.containers.getPlayerContainerCursorContainer(); + BedrockContainer containerForClickedSlot = ScreenHandlerTranslatorManager.getBedrockContainerFromJava(screenHandler, clickedSlotId); - if (containerForClickedSlot == null) { - System.out.println("FIX THIS, unknown slot clicked " + clickedSlotId); - return; - } + if (containerForClickedSlot == null) { + System.out.println("FIX THIS, unknown slot clicked " + clickedSlotId); + return; + } - int bedrockSlotId = ScreenHandlerTranslatorManager.getBedrockSlotFromJavaContainer(screenHandler, clickedSlotId, containerForClickedSlot); + int bedrockSlotId = ScreenHandlerTranslatorManager.getBedrockSlotFromJavaContainer(screenHandler, clickedSlotId, containerForClickedSlot); - ItemData cursorItemData = cursorContainer.getItemFromSlot(0); + ItemData cursorItemData = cursorContainer.getItemFromSlot(0); - { - //decrease if the user right clicked a slot, change to air if they left clicked a slot - ItemData decreasedCursorStack = ItemDataUtils.copyWithCount(cursorItemData, cursorItemData.getCount() - itemCountToMoveFromCursorToClickedSlot); - if (decreasedCursorStack.getCount() == 0) { - decreasedCursorStack = ItemData.AIR; - } - - InventoryActionData decreaseCursorStack = new InventoryActionData(InventorySource.fromContainerWindowId(cursorContainer.getId()), 0, cursorItemData, decreasedCursorStack); - inventoryTransactionPacket.getActions().add(decreaseCursorStack); - cursorContainer.setItemBedrock(0, decreasedCursorStack); - } + // Decrease if the user right clicked a slot, change to air if they left clicked a slot. + ItemData decreasedCursorStack = ItemDataUtils.copyWithCount(cursorItemData, cursorItemData.getCount() - itemCountToMoveFromCursorToClickedSlot); + if (decreasedCursorStack.getCount() == 0) { + decreasedCursorStack = ItemData.AIR; + } - { - ItemData clickedSlotNewItemData = ItemDataUtils.copyWithCount(cursorItemData, itemCountToMoveFromCursorToClickedSlot); + InventoryActionData decreaseCursorStack = new InventoryActionData(InventorySource.fromContainerWindowId(cursorContainer.getId()), 0, cursorItemData, decreasedCursorStack); + inventoryTransactionPacket.getActions().add(decreaseCursorStack); + cursorContainer.setItemBedrock(0, decreasedCursorStack); - //changes it to the cursor slot stack - InventoryActionData incrementClickedSlotWithCursorStack = new InventoryActionData(InventorySource.fromContainerWindowId(containerForClickedSlot.getId()), bedrockSlotId, ItemData.AIR, clickedSlotNewItemData); - inventoryTransactionPacket.getActions().add(incrementClickedSlotWithCursorStack); - containerForClickedSlot.setItemBedrock(bedrockSlotId, clickedSlotNewItemData); - } + ItemData clickedSlotNewItemData = ItemDataUtils.copyWithCount(cursorItemData, itemCountToMoveFromCursorToClickedSlot); - } + // Changes it to the cursor slot stack. + InventoryActionData incrementClickedSlotWithCursorStack = new InventoryActionData(InventorySource.fromContainerWindowId(containerForClickedSlot.getId()), bedrockSlotId, ItemData.AIR, clickedSlotNewItemData); + inventoryTransactionPacket.getActions().add(incrementClickedSlotWithCursorStack); + containerForClickedSlot.setItemBedrock(bedrockSlotId, clickedSlotNewItemData); Client.instance.sendPacket(inventoryTransactionPacket); diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClientCommandC2SPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClientCommandC2SPacketTranslator.java index b3c912f..5692c1e 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClientCommandC2SPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/ClientCommandC2SPacketTranslator.java @@ -14,7 +14,9 @@ public class ClientCommandC2SPacketTranslator extends PacketTranslator getPacketClass() { return ClientStatusC2SPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/CloseHandledScreenC2SPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/CloseHandledScreenC2SPacketTranslator.java index 82f60ba..2c64608 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/CloseHandledScreenC2SPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/javaconnection/packet/CloseHandledScreenC2SPacketTranslator.java @@ -11,9 +11,14 @@ public class CloseHandledScreenC2SPacketTranslator extends PacketTranslator getPacketClass() { @EventTarget public void event(EventPlayerTick event) { + if (TunnelMC.mc.player == null) { + return; + } int runtimeId = TunnelMC.mc.player.getEntityId(); PlayerActionType action = PlayerActionType.CONTINUE_BREAK; diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/EntityTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/EntityTranslator.java index e2caa1a..5bca883 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/EntityTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/EntityTranslator.java @@ -15,26 +15,24 @@ public class EntityTranslator { - public static final HashMap> BEDROCK_IDENTIFIER_TO_ENTITY_TYPE = new HashMap>(); + public static final HashMap> BEDROCK_IDENTIFIER_TO_ENTITY_TYPE = new HashMap<>(); public static void load() { - List> allEntityTypes = Registry.ENTITY_TYPE.stream().collect(Collectors.toList()); for (EntityType e : allEntityTypes) { BEDROCK_IDENTIFIER_TO_ENTITY_TYPE.put(EntityType.getId(e).toString(), e); } - JsonObject jsonObject = TunnelMC.instance.fileManagement.getJsonObjectFromResource("tunnelmc/entity override translations.json"); + JsonObject jsonObject = TunnelMC.instance.fileManagement.getJsonObjectFromResource("tunnel/entity_override_translations.json"); if (jsonObject == null) { return; } for (Map.Entry entry : jsonObject.entrySet()) { - Optional> optional = EntityType.get(entry.getValue().getAsString()); if (!optional.isPresent()) { - System.out.println("Could not find entity type " + entry.getValue().getAsString() + " when reading entity override translations.json"); + System.out.println("Could not find entity type " + entry.getValue().getAsString() + " when reading entity_override_translations.json"); continue; } @@ -43,4 +41,4 @@ public static void load() { } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/GeneralTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/GeneralTranslator.java deleted file mode 100644 index c7b87fa..0000000 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/GeneralTranslator.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.THEREALWWEFAN231.tunnelmc.translator; - -public abstract class GeneralTranslator { - - public abstract V translate(K before); - -} diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslator.java index f3617d1..b3ad7cf 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslator.java @@ -4,10 +4,10 @@ public abstract class PacketTranslator { public abstract void translate(T packet); - public abstract Class getPacketClass();//i could use reflection but it generally wouldn't be ideal - - public boolean idleUntil() {//if the packet was sent before something(example player or world not being null) - return true; + public abstract Class getPacketClass(); + + public boolean idleUntil() { + return false; } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslatorManager.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslatorManager.java index c57627f..20313a5 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslatorManager.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/PacketTranslatorManager.java @@ -19,14 +19,13 @@ public class PacketTranslatorManager { private final Map, PacketTranslator> packetTranslatorsByPacketClass = new HashMap<>(); - - private final CopyOnWriteArrayList idlePackets = new CopyOnWriteArrayList<>();//I didn't actually check if I need CopyOnWriteArrayList, but I assume so + private final CopyOnWriteArrayList idlePackets = new CopyOnWriteArrayList<>(); public PacketTranslatorManager() { this.addTranslator(new StartGameTranslator()); this.addTranslator(new ChunkRadiusUpdatedTranslator()); this.addTranslator(new LevelChunkTranslator()); - this.addTranslator(new PlayStatusPacketTranslator()); + this.addTranslator(new NetworkStackLatencyPacketTranslator()); this.addTranslator(new ResourcePacksInfoPacketTranslator()); this.addTranslator(new ResourcePackStackPacketTranslator()); this.addTranslator(new AddPlayerTranslator()); @@ -73,36 +72,37 @@ private void addTranslator(PacketTranslator translator) { public void translatePacket(BedrockPacket bedrockPacket) { PacketTranslator packetTranslator = (PacketTranslator) this.packetTranslatorsByPacketClass.get(bedrockPacket.getClass()); if (packetTranslator != null) { - if (!packetTranslator.idleUntil()) {//if false we have to wait - this.idlePackets.add(new IdleThing(packetTranslator, bedrockPacket)); + if (packetTranslator.idleUntil()) { + this.idlePackets.add(new IdlePacket(packetTranslator, bedrockPacket)); return; } packetTranslator.translate(bedrockPacket); } else { - //System.out.println("Could not find a packet translator for the packet: " + bedrockPacket.getClass()); + System.out.println("Couldn't find a packet translator for the packet: " + bedrockPacket.getClass()); } } @EventTarget public void onEvent(EventPlayerTick event) { for (int i = 0; i < this.idlePackets.size(); i++) { - IdleThing idleThing = this.idlePackets.get(i); - if (!idleThing.packetTranslator.idleUntil()) {//still need to wait + IdlePacket idlePacket = this.idlePackets.get(i); + if (idlePacket.packetTranslator.idleUntil()) { continue; } - idleThing.getPacketTranslator().translate(idleThing.getBedrockPacket()); + idlePacket.getPacketTranslator().translate(idlePacket.getBedrockPacket()); this.idlePackets.remove(i); i--; } } - private static class IdleThing { + private static class IdlePacket { + private final PacketTranslator packetTranslator; private final BedrockPacket bedrockPacket; - public IdleThing(PacketTranslator packetTranslator, BedrockPacket bedrockPacket) { + public IdlePacket(PacketTranslator packetTranslator, BedrockPacket bedrockPacket) { this.packetTranslator = packetTranslator; this.bedrockPacket = bedrockPacket; } @@ -116,4 +116,4 @@ public BedrockPacket getBedrockPacket() { } } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/BlockStateTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/BlockStateTranslator.java index ebf7bb6..1a79cbe 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/BlockStateTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/BlockStateTranslator.java @@ -83,7 +83,7 @@ public static void load() { } - InputStream stream = FileManagement.class.getClassLoader().getResourceAsStream("tunnelmc/blockpalette.nbt"); + InputStream stream = FileManagement.class.getClassLoader().getResourceAsStream("tunnel/block_palette.nbt"); if (stream == null) { throw new RuntimeException("Could not find the block palette file!"); } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/LegacyBlockPaletteManager.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/LegacyBlockPaletteManager.java index ef94724..64ced97 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/LegacyBlockPaletteManager.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/blockstate/LegacyBlockPaletteManager.java @@ -22,7 +22,7 @@ public final class LegacyBlockPaletteManager { static { NbtList legacyBlockStates; - try (InputStream stream = FileManagement.class.getClassLoader().getResourceAsStream("tunnelmc/runtime_block_states.dat")) { + try (InputStream stream = FileManagement.class.getClassLoader().getResourceAsStream("tunnel/runtime_block_states.dat")) { if (stream == null) { throw new AssertionError("Unable to locate block state tag!"); } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/item/ItemTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/item/ItemTranslator.java index a7fd02c..724346d 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/item/ItemTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/item/ItemTranslator.java @@ -27,7 +27,6 @@ public class ItemTranslator { public static final HashMap BEDROCK_ITEM_INFO_TO_JAVA_ITEM = new HashMap<>(); public static void load() { - JsonObject jsonObject = TunnelMC.instance.fileManagement.getJsonObjectFromResource("geyser/items.json"); if (jsonObject == null) { throw new RuntimeException("Items list not found!"); @@ -55,7 +54,6 @@ public static void load() { //TODO: tags and what ever public static ItemStack itemDataToItemStack(ItemData itemData) { - int damage = 0; if (itemData.getTag() != null) { damage = itemData.getTag().getInt("Damage"); diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/AdventureSettingsTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/AdventureSettingsTranslator.java index 62c8ae9..f309ea1 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/AdventureSettingsTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/AdventureSettingsTranslator.java @@ -8,6 +8,7 @@ import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket; public class AdventureSettingsTranslator extends PacketTranslator { + @Override public void translate(AdventureSettingsPacket packet) { PlayerAbilities abilities = new PlayerAbilities(); @@ -24,4 +25,5 @@ public void translate(AdventureSettingsPacket packet) { public Class getPacketClass() { return AdventureSettingsPacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/BlockEntityDataPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/BlockEntityDataPacketTranslator.java index 3dd68d9..089fe4f 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/BlockEntityDataPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/BlockEntityDataPacketTranslator.java @@ -11,7 +11,6 @@ public class BlockEntityDataPacketTranslator extends PacketTranslator { @@ -12,10 +13,13 @@ public void translate(DisconnectPacket packet) { if (MinecraftClient.getInstance().world != null) { MinecraftClient.getInstance().world.disconnect(); } - MinecraftClient.getInstance().execute(() -> - MinecraftClient.getInstance().disconnect( - new DisconnectedScreen(MinecraftClient.getInstance().currentScreen, Text.of("Use Translated Here"), - Text.of(packet.getKickMessage())))); + MinecraftClient.getInstance().execute(() -> MinecraftClient.getInstance().disconnect( + new DisconnectedScreen( + new TitleScreen(false), + Text.of("TunnelMC"), + Text.of(packet.getKickMessage()) + ) + )); } @Override diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/GameRulesChangedTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/GameRulesChangedTranslator.java index ad50ec1..55eb8f4 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/GameRulesChangedTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/GameRulesChangedTranslator.java @@ -9,6 +9,7 @@ import java.util.List; public class GameRulesChangedTranslator extends PacketTranslator { + @Override public void translate(GameRulesChangedPacket packet) { if (MinecraftClient.getInstance().world == null) { @@ -24,19 +25,22 @@ public Class getPacketClass() { } public static void onGameRulesChanged(List> gamerules) { - if (MinecraftClient.getInstance().world == null) { + if (MinecraftClient.getInstance().world == null || MinecraftClient.getInstance().player == null) { return; } - for (GameRuleData gamerule : gamerules) { - switch (gamerule.getName()) { - case "dodaylightcycle": - MinecraftClient.getInstance().world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(((Boolean) gamerule.getValue()), null); + for (GameRuleData gameRule : gamerules) { + switch (gameRule.getName()) { + case "dodaylightcycle": { + MinecraftClient.getInstance().world.getGameRules().get(GameRules.DO_DAYLIGHT_CYCLE).set(((Boolean) gameRule.getValue()), null); break; - case "doimmediaterespawn": - MinecraftClient.getInstance().player.setShowsDeathScreen(!((Boolean) gamerule.getValue())); + } + case "doimmediaterespawn": { + MinecraftClient.getInstance().player.setShowsDeathScreen(!((Boolean) gameRule.getValue())); break; + } } } } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/NetworkStackLatencyPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/NetworkStackLatencyPacketTranslator.java new file mode 100644 index 0000000..1dba6f5 --- /dev/null +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/NetworkStackLatencyPacketTranslator.java @@ -0,0 +1,23 @@ +package me.THEREALWWEFAN231.tunnelmc.translator.packet; + +import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; +import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; +import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; + +public class NetworkStackLatencyPacketTranslator extends PacketTranslator { + + @Override + public void translate(NetworkStackLatencyPacket packet) { + if (packet.isFromServer()) { + NetworkStackLatencyPacket resp = new NetworkStackLatencyPacket(); + resp.setTimestamp(System.currentTimeMillis()); + Client.instance.sendPacketImmediately(resp); + } + } + + @Override + public Class getPacketClass() { + return NetworkStackLatencyPacket.class; + } + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/PlayStatusPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/PlayStatusPacketTranslator.java deleted file mode 100644 index a0283f8..0000000 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/PlayStatusPacketTranslator.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.THEREALWWEFAN231.tunnelmc.translator.packet; - -import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; -import com.nukkitx.protocol.bedrock.packet.RequestChunkRadiusPacket; - -import me.THEREALWWEFAN231.tunnelmc.TunnelMC; -import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; -import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; - -public class PlayStatusPacketTranslator extends PacketTranslator { - - @Override - public void translate(PlayStatusPacket packet) { - if (packet.getStatus() == PlayStatusPacket.Status.PLAYER_SPAWN) { -// RequestChunkRadiusPacket requestChunkRadiusPacket = new RequestChunkRadiusPacket(); -// requestChunkRadiusPacket.setRadius(TunnelMC.mc.options.viewDistance); -// -// Client.instance.sendPacketImmediately(requestChunkRadiusPacket); hmm - } - } - - @Override - public Class getPacketClass() { - return PlayStatusPacket.class; - } - -} diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePackStackPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePackStackPacketTranslator.java index 5091281..0f7564a 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePackStackPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePackStackPacketTranslator.java @@ -2,7 +2,6 @@ import com.nukkitx.protocol.bedrock.packet.ResourcePackClientResponsePacket; import com.nukkitx.protocol.bedrock.packet.ResourcePackStackPacket; - import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; @@ -21,4 +20,4 @@ public Class getPacketClass() { return ResourcePackStackPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePacksInfoPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePacksInfoPacketTranslator.java index 5ac5fdc..fdd1e15 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePacksInfoPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ResourcePacksInfoPacketTranslator.java @@ -3,7 +3,6 @@ import com.nukkitx.protocol.bedrock.packet.ClientCacheStatusPacket; import com.nukkitx.protocol.bedrock.packet.ResourcePackClientResponsePacket; import com.nukkitx.protocol.bedrock.packet.ResourcePacksInfoPacket; - import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; @@ -24,4 +23,4 @@ public Class getPacketClass() { return ResourcePacksInfoPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ServerToClientHandshakePacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ServerToClientHandshakePacketTranslator.java index 186ea50..589fb1a 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ServerToClientHandshakePacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/ServerToClientHandshakePacketTranslator.java @@ -1,24 +1,22 @@ package me.THEREALWWEFAN231.tunnelmc.translator.packet; -import java.security.interfaces.ECPublicKey; -import java.util.Base64; - -import javax.crypto.SecretKey; - import com.google.gson.JsonObject; import com.nukkitx.protocol.bedrock.packet.ClientToServerHandshakePacket; import com.nukkitx.protocol.bedrock.packet.ServerToClientHandshakePacket; import com.nukkitx.protocol.bedrock.util.EncryptionUtils; - import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; +import javax.crypto.SecretKey; +import java.security.interfaces.ECPublicKey; +import java.util.Base64; + public class ServerToClientHandshakePacketTranslator extends PacketTranslator { @Override public void translate(ServerToClientHandshakePacket packet) { - // Thanks to proxypass, manually parse the jwt, as said in Xbox, this would be easier using the jwt library but I like seeing what's actually happening + // Thanks to ProxyPass for this portion of the code. try { String[] jwtSplit = packet.getJwt().split("\\."); String header = new String(Base64.getDecoder().decode(jwtSplit[0])); @@ -29,6 +27,7 @@ public void translate(ServerToClientHandshakePacket packet) { ECPublicKey serverKey = EncryptionUtils.generateKey(headerObject.get("x5u").getAsString()); SecretKey key = EncryptionUtils.getSecretKey(Client.instance.authData.getPrivateKey(), serverKey, Base64.getDecoder().decode(payloadObject.get("salt").getAsString())); + Client.instance.bedrockClient.getSession().enableEncryption(key); } catch (Exception e) { e.printStackTrace(); @@ -36,7 +35,6 @@ public void translate(ServerToClientHandshakePacket packet) { ClientToServerHandshakePacket clientToServerHandshake = new ClientToServerHandshakePacket(); Client.instance.sendPacketImmediately(clientToServerHandshake); - } @Override @@ -44,4 +42,4 @@ public Class getPacketClass() { return ServerToClientHandshakePacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/SetPlayerGameTypeTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/SetPlayerGameTypeTranslator.java index 12d6963..df0eb95 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/SetPlayerGameTypeTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/SetPlayerGameTypeTranslator.java @@ -7,6 +7,7 @@ import net.minecraft.world.GameMode; public class SetPlayerGameTypeTranslator extends PacketTranslator { + @Override public void translate(SetPlayerGameTypePacket packet) { GameMode javaGameMode; @@ -21,7 +22,7 @@ public void translate(SetPlayerGameTypePacket packet) { javaGameMode = GameMode.ADVENTURE; break; default: - System.out.println("Don't know how to process " + packet.toString()); + System.out.println("Couldn't find the Java game mode for: " + packet.getGamemode()); return; } @@ -34,4 +35,5 @@ public void translate(SetPlayerGameTypePacket packet) { public Class getPacketClass() { return SetPlayerGameTypePacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/StartGameTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/StartGameTranslator.java index 93eff6b..432f6c5 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/StartGameTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/StartGameTranslator.java @@ -1,15 +1,9 @@ package me.THEREALWWEFAN231.tunnelmc.translator.packet; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - import com.nukkitx.protocol.bedrock.data.GameRuleData; -import com.nukkitx.protocol.bedrock.data.GameType; import com.nukkitx.protocol.bedrock.packet.RequestChunkRadiusPacket; import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; - import com.nukkitx.protocol.bedrock.packet.TickSyncPacket; import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; @@ -27,16 +21,14 @@ import net.minecraft.world.World; import net.minecraft.world.dimension.DimensionType; -public class StartGameTranslator extends PacketTranslator { +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; - public static int lastRunTimeId;//TODO: remove this, or at least move to some class accessible from the Client class, thinking of setting the player id to this, but not sure about that yet - public static GameType DEFAULT_GAME_TYPE; +public class StartGameTranslator extends PacketTranslator { @Override public void translate(StartGamePacket packet) { - int playerEntityId = (int) packet.getRuntimeEntityId();//not sure if we are suppose to use runtime id or unique id - lastRunTimeId = playerEntityId; - for (StartGamePacket.ItemEntry itemEntry : packet.getItemEntries()) { if (itemEntry.getIdentifier().equals("minecraft:shield")) { Client.instance.bedrockClient.getSession().getHardcodedBlockingId().set(itemEntry.getId()); @@ -44,38 +36,37 @@ public void translate(StartGamePacket packet) { } } - DEFAULT_GAME_TYPE = packet.getLevelGameType(); + Client.instance.entityRuntimeId = (int) packet.getRuntimeEntityId(); + Client.instance.defaultGameMode = packet.getLevelGameType(); + GameMode gameMode = GameModeTranslator.bedrockToJava(packet.getPlayerGameType(), packet.getLevelGameType()); GameMode previousGameMode = GameMode.NOT_SET; - long sha256Seed = packet.getSeed(); - boolean hardcore = false; - Set> dimensionIds = new HashSet<>();//im not quite sure if it needs to be linked, it would appear not as ClientPlayNetworkHandler shuffles them + Set> dimensionIds = new HashSet<>(); dimensionIds.add(World.NETHER); dimensionIds.add(World.OVERWORLD); dimensionIds.add(World.END); DynamicRegistryManager.Impl registryManager = DynamicRegistryManager.create(); DimensionType dimensionType = DimensionTranslator.bedrockToJava(packet.getDimensionId()); RegistryKey dimensionId = DimensionTranslator.bedrockToJavaRegistryKey(packet.getDimensionId()); + + int seed = packet.getSeed(); int maxPlayers = 999; int chunkLoadDistance = 3; - boolean reducedDebugInfo = false; boolean showDeathScreen = true; - boolean debugWorld = false; - boolean flatWorld = false; - for (GameRuleData gamerule : packet.getGamerules()) { - if ("doimmediaterespawn".equals(gamerule.getName())) { - showDeathScreen = !((Boolean) gamerule.getValue()); + for (GameRuleData gameRule : packet.getGamerules()) { + if (gameRule.getName().equals("doimmediaterespawn")) { + showDeathScreen = !((Boolean) gameRule.getValue()); break; } } - GameJoinS2CPacket gameJoinS2CPacket = new GameJoinS2CPacket(playerEntityId, gameMode, previousGameMode, sha256Seed, hardcore, dimensionIds, registryManager, dimensionType, dimensionId, maxPlayers, chunkLoadDistance, reducedDebugInfo, showDeathScreen, debugWorld, flatWorld); + GameJoinS2CPacket gameJoinS2CPacket = new GameJoinS2CPacket(Client.instance.entityRuntimeId, gameMode, previousGameMode, seed, false, dimensionIds, registryManager, dimensionType, dimensionId, maxPlayers, chunkLoadDistance, false, showDeathScreen, false, false); Client.instance.javaConnection.processServerToClientPacket(gameJoinS2CPacket); Client.instance.onPlayerInitialized(); - //TODO send a complete SynchronizeTagsS2CPacket - that way water can work + // TODO: Send a complete SynchronizeTagsS2CPacket so that water can work. MinecraftClient.getInstance().execute(() -> GameRulesChangedTranslator.onGameRulesChanged(packet.getGamerules())); @@ -85,15 +76,16 @@ public void translate(StartGamePacket packet) { float yaw = packet.getRotation().getX(); float pitch = packet.getRotation().getY(); int teleportId = 0; + PlayerPositionLookS2CPacket playerPositionLookS2CPacket = new PlayerPositionLookS2CPacket(x, y, z, yaw, pitch, Collections.emptySet(), teleportId); Client.instance.javaConnection.processServerToClientPacket(playerPositionLookS2CPacket); int chunkX = MathHelper.floor(x) >> 4; int chunkZ = MathHelper.floor(z) >> 4; + ChunkRenderDistanceCenterS2CPacket chunkRenderDistanceCenterS2CPacket = new ChunkRenderDistanceCenterS2CPacket(chunkX, chunkZ); Client.instance.javaConnection.processServerToClientPacket(chunkRenderDistanceCenterS2CPacket); - // Boilerplate initialization stuff RequestChunkRadiusPacket requestChunkRadiusPacket = new RequestChunkRadiusPacket(); requestChunkRadiusPacket.setRadius(TunnelMC.mc.options.viewDistance); Client.instance.sendPacketImmediately(requestChunkRadiusPacket); @@ -101,7 +93,7 @@ public void translate(StartGamePacket packet) { Client.instance.sendPacketImmediately(new TickSyncPacket()); SetLocalPlayerAsInitializedPacket setLocalPlayerAsInitializedPacket = new SetLocalPlayerAsInitializedPacket(); - setLocalPlayerAsInitializedPacket.setRuntimeEntityId(lastRunTimeId); + setLocalPlayerAsInitializedPacket.setRuntimeEntityId(Client.instance.entityRuntimeId); Client.instance.sendPacketImmediately(setLocalPlayerAsInitializedPacket); } @@ -110,4 +102,4 @@ public Class getPacketClass() { return StartGamePacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/TextTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/TextTranslator.java index b7a2d89..3dc048e 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/TextTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/TextTranslator.java @@ -19,17 +19,17 @@ public void translate(TextPacket packet) { System.out.println("Falling back to raw translation for " + packet.toString()); } case RAW: { - GameMessageS2CPacket gameMessageS2CPacket = new GameMessageS2CPacket(new LiteralText(packet.getMessage()), - MessageType.CHAT, new UUID(0, 0)); - + GameMessageS2CPacket gameMessageS2CPacket = new GameMessageS2CPacket(new LiteralText(packet.getMessage()), MessageType.CHAT, new UUID(0, 0)); Client.instance.javaConnection.processServerToClientPacket(gameMessageS2CPacket); break; } case CHAT: { - String formattedChatMessage = "<" + packet.getSourceName() + "> " + packet.getMessage(); - GameMessageS2CPacket gameMessageS2CPacket = new GameMessageS2CPacket(new LiteralText(formattedChatMessage), - MessageType.CHAT, null); + String formattedChatMessage = packet.getMessage(); + if (packet.getSourceName().length() > 0) { + formattedChatMessage = "<" + packet.getSourceName() + "> " + formattedChatMessage; + } + GameMessageS2CPacket gameMessageS2CPacket = new GameMessageS2CPacket(new LiteralText(formattedChatMessage), MessageType.CHAT, null); Client.instance.javaConnection.processServerToClientPacket(gameMessageS2CPacket); break; } @@ -40,4 +40,5 @@ public void translate(TextPacket packet) { public Class getPacketClass() { return TextPacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/UpdatePlayerGameTypeTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/UpdatePlayerGameTypeTranslator.java index f2c3871..5cfef4d 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/UpdatePlayerGameTypeTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/UpdatePlayerGameTypeTranslator.java @@ -8,9 +8,10 @@ import net.minecraft.world.GameMode; public class UpdatePlayerGameTypeTranslator extends PacketTranslator { + @Override public void translate(UpdatePlayerGameTypePacket packet) { - GameMode javaGameMode = GameModeTranslator.bedrockToJava(packet.getGameType(), StartGameTranslator.DEFAULT_GAME_TYPE); + GameMode javaGameMode = GameModeTranslator.bedrockToJava(packet.getGameType(), Client.instance.defaultGameMode); Client.instance.javaConnection.processServerToClientPacket(new GameStateChangeS2CPacket( GameStateChangeS2CPacket.GAME_MODE_CHANGED, @@ -21,4 +22,5 @@ public void translate(UpdatePlayerGameTypePacket packet) { public Class getPacketClass() { return UpdatePlayerGameTypePacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddEntityPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddEntityPacketTranslator.java index d7746ba..f632e95 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddEntityPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddEntityPacketTranslator.java @@ -13,38 +13,40 @@ public class AddEntityPacketTranslator extends PacketTranslator { - //TODO: handle non living entities differently, EntitySpawnS2CPacket + // TODO: Handle non living entities differently, with the EntitySpawnS2CPacket. @SuppressWarnings("unchecked") @Override public void translate(AddEntityPacket packet) { - EntityType entityType = EntityTranslator.BEDROCK_IDENTIFIER_TO_ENTITY_TYPE.get(packet.getIdentifier()); if (entityType == null) { - System.out.println("Could not find entity type " + packet.getIdentifier()); + System.out.println("Could not find entity type: " + packet.getIdentifier()); + return; + } + + int id = (int) packet.getUniqueEntityId(); + double x = packet.getPosition().getX(); + double y = packet.getPosition().getY(); + double z = packet.getPosition().getZ(); + double motionX = packet.getMotion().getX(); + double motionY = packet.getMotion().getY(); + double motionZ = packet.getMotion().getZ(); + float yaw = packet.getRotation().getY(); + float pitch = packet.getRotation().getX(); + + Entity entity = entityType.create(TunnelMC.mc.world); + if (entity == null) { + System.out.println("Could not create entity type: " + packet.getIdentifier()); return; - } else { - - int id = (int) packet.getUniqueEntityId(); - double x = packet.getPosition().getX(); - double y = packet.getPosition().getY(); - double z = packet.getPosition().getZ(); - double motionX = packet.getMotion().getX(); - double motionY = packet.getMotion().getY(); - double motionZ = packet.getMotion().getZ(); - float yaw = packet.getRotation().getY();//TODO: not sure about these - float pitch = packet.getRotation().getX(); - - Entity entity = entityType.create(TunnelMC.mc.world); - entity.setEntityId(id); - entity.setPos(x, y, z); - entity.setVelocity(motionX, motionY, motionZ); - entity.yaw = yaw; - entity.pitch = pitch; - - Client.instance.javaConnection.processServerToClientPacket((Packet) entity.createSpawnPacket()); } + entity.setEntityId(id); + entity.setPos(x, y, z); + entity.setVelocity(motionX, motionY, motionZ); + entity.yaw = yaw; + entity.pitch = pitch; + + Client.instance.javaConnection.processServerToClientPacket((Packet) entity.createSpawnPacket()); } @Override @@ -52,4 +54,4 @@ public Class getPacketClass() { return AddEntityPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddItemEntityPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddItemEntityPacketTranslator.java index 3a981bf..724d4d5 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddItemEntityPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddItemEntityPacketTranslator.java @@ -20,7 +20,6 @@ public class AddItemEntityPacketTranslator extends PacketTranslator getPacketClass() { return AddItemEntityPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddPlayerTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddPlayerTranslator.java index a817f6b..9e484aa 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddPlayerTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AddPlayerTranslator.java @@ -23,13 +23,17 @@ public class AddPlayerTranslator extends PacketTranslator { @Override public void translate(AddPlayerPacket packet) { + if (TunnelMC.mc.world == null) { + return; + } + int id = (int) packet.getRuntimeEntityId(); UUID uuid = packet.getUuid(); String name = packet.getUsername(); double x = packet.getPosition().getX(); double y = packet.getPosition().getY(); double z = packet.getPosition().getZ(); - float pitch = packet.getRotation().getX();//TODO: not sure about these + float pitch = packet.getRotation().getX(); float yaw = packet.getRotation().getY(); Vec3d velocity = new Vec3d(packet.getMotion().getX(), packet.getMotion().getY(), packet.getMotion().getZ()); @@ -49,6 +53,7 @@ public void translate(AddPlayerPacket packet) { Collections.singletonList(itemStackPair)); Client.instance.javaConnection.processServerToClientPacket(equipmentUpdatePacket); }; + if (TunnelMC.mc.world != null) { runnable.run(); } else { @@ -61,4 +66,4 @@ public Class getPacketClass() { return AddPlayerPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AnimateTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AnimateTranslator.java index 3965468..fd63973 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AnimateTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/AnimateTranslator.java @@ -8,21 +8,21 @@ import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; public class AnimateTranslator extends PacketTranslator { + @Override public void translate(AnimatePacket packet) { if (TunnelMC.mc.world == null) { return; } + Entity entity = TunnelMC.mc.world.getEntityById((int) packet.getRuntimeEntityId()); if (entity == null) { return; } - switch (packet.getAction()) { - case SWING_ARM: - EntityAnimationS2CPacket swingArmPacket = new EntityAnimationS2CPacket(entity, 0); - Client.instance.javaConnection.processServerToClientPacket(swingArmPacket); - break; + if (packet.getAction() == AnimatePacket.Action.SWING_ARM) { + EntityAnimationS2CPacket swingArmPacket = new EntityAnimationS2CPacket(entity, 0); + Client.instance.javaConnection.processServerToClientPacket(swingArmPacket); } } @@ -30,4 +30,5 @@ public void translate(AnimatePacket packet) { public Class getPacketClass() { return AnimatePacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobArmorEquipmentTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobArmorEquipmentTranslator.java index cbd6710..93e8f53 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobArmorEquipmentTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobArmorEquipmentTranslator.java @@ -14,6 +14,7 @@ import java.util.List; public class MobArmorEquipmentTranslator extends PacketTranslator { + @Override public void translate(MobArmorEquipmentPacket packet) { List> javaArmorSlots = new ObjectArrayList<>(4); @@ -35,4 +36,5 @@ public Class getPacketClass() { private Pair translateArmorSlot(ItemData bedrockItem, EquipmentSlot slot) { return new Pair<>(slot, ItemTranslator.itemDataToItemStack(bedrockItem)); } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobEquipmentTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobEquipmentTranslator.java index 921092b..6f3280f 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobEquipmentTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MobEquipmentTranslator.java @@ -12,13 +12,11 @@ import java.util.Collections; -/** - * Sent when an entity changes their main hand or offhand - */ public class MobEquipmentTranslator extends PacketTranslator { + @Override public void translate(MobEquipmentPacket packet) { - EquipmentSlot equipmentSlot = null; + EquipmentSlot equipmentSlot; switch (packet.getContainerId()) { case ContainerId.INVENTORY: equipmentSlot = EquipmentSlot.MAINHAND; @@ -26,20 +24,20 @@ public void translate(MobEquipmentPacket packet) { case ContainerId.OFFHAND: equipmentSlot = EquipmentSlot.OFFHAND; break; + default: + System.out.println("Not sure how to handle MobEquipmentPacket: " + packet.toString()); + return; } - if (equipmentSlot != null) { - Pair itemStackPair = new Pair<>(equipmentSlot, ItemTranslator.itemDataToItemStack(packet.getItem())); - EntityEquipmentUpdateS2CPacket equipmentUpdatePacket = new EntityEquipmentUpdateS2CPacket((int) packet.getRuntimeEntityId(), - Collections.singletonList(itemStackPair)); - Client.instance.javaConnection.processServerToClientPacket(equipmentUpdatePacket); - } else { - System.out.println("Not sure how to handle MobEquipmentPacket: " + packet.toString()); - } + Pair itemStackPair = new Pair<>(equipmentSlot, ItemTranslator.itemDataToItemStack(packet.getItem())); + EntityEquipmentUpdateS2CPacket equipmentUpdatePacket = new EntityEquipmentUpdateS2CPacket((int) packet.getRuntimeEntityId(), + Collections.singletonList(itemStackPair)); + Client.instance.javaConnection.processServerToClientPacket(equipmentUpdatePacket); } @Override public Class getPacketClass() { return MobEquipmentPacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MoveEntityAbsolutePacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MoveEntityAbsolutePacketTranslator.java index c846818..8a41dd2 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MoveEntityAbsolutePacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MoveEntityAbsolutePacketTranslator.java @@ -13,7 +13,6 @@ public class MoveEntityAbsolutePacketTranslator extends PacketTranslator getPacketClass() { return MoveEntityAbsolutePacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MovePlayerPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MovePlayerPacketTranslator.java index 0aa1f08..c00efab 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MovePlayerPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/MovePlayerPacketTranslator.java @@ -68,7 +68,7 @@ public Class getPacketClass() { @Override public boolean idleUntil() { - return TunnelMC.mc.player != null; + return TunnelMC.mc.player == null; } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/PlayerListPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/PlayerListPacketTranslator.java index df1b0da..4004fda 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/PlayerListPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/PlayerListPacketTranslator.java @@ -27,9 +27,6 @@ public void translate(PlayerListPacket packet) { ((IMixinPlayerListS2CPacket) playerListS2CPacket).setEntries(entries); for (PlayerListPacket.Entry entry : packet.getEntries()) { - if (add) { - - } // gamemode says nullable but is used in ClientGameSession/: entries.add(playerListS2CPacket.new Entry(new GameProfile(entry.getUuid(), entry.getName()), 0, GameMode.SURVIVAL, new LiteralText(entry.getName()))); @@ -43,16 +40,4 @@ public Class getPacketClass() { return PlayerListPacket.class; } - public static class SkinType {//this is only temporary - - public Identifier texture; - public boolean slim; - - public SkinType(Identifier texture, boolean slim) { - this.texture = texture; - this.slim = slim; - } - - } - } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RemoveEntityPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RemoveEntityPacketTranslator.java index dccb4cb..432f016 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RemoveEntityPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RemoveEntityPacketTranslator.java @@ -10,11 +10,9 @@ public class RemoveEntityPacketTranslator extends PacketTranslator getPacketClass() { return RemoveEntityPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RespawnPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RespawnPacketTranslator.java index 608750e..c46d1cc 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RespawnPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/RespawnPacketTranslator.java @@ -10,6 +10,7 @@ import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; import me.THEREALWWEFAN231.tunnelmc.mixins.interfaces.IMixinDimensionType; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; +import net.minecraft.client.MinecraftClient; import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; import net.minecraft.world.GameMode; import net.minecraft.world.World; @@ -18,13 +19,11 @@ public class RespawnPacketTranslator extends PacketTranslator { @Override public void translate(RespawnPacket packet) { - - if (packet.getState() == State.SERVER_SEARCHING) {//display death screen? - + if (TunnelMC.mc.player == null || MinecraftClient.getInstance().interactionManager == null) { + return; } if (packet.getState() == State.SERVER_READY) { - PlayerActionPacket playerActionPacket = new PlayerActionPacket(); playerActionPacket.setRuntimeEntityId(TunnelMC.mc.player.getEntityId()); playerActionPacket.setAction(PlayerActionType.RESPAWN); @@ -33,8 +32,9 @@ public void translate(RespawnPacket packet) { Client.instance.sendPacket(playerActionPacket); - //TODO: correct these values, so like it's not just overworld, and survival - PlayerRespawnS2CPacket playerRespawnS2CPacket = new PlayerRespawnS2CPacket(IMixinDimensionType.getOverworld(), World.OVERWORLD, -1, GameMode.SURVIVAL, GameMode.SURVIVAL, false, false, false); + // TODO: Correct the dimension value so it's not just over world. + GameMode gameMode = MinecraftClient.getInstance().interactionManager.getCurrentGameMode(); + PlayerRespawnS2CPacket playerRespawnS2CPacket = new PlayerRespawnS2CPacket(IMixinDimensionType.getOverworld(), World.OVERWORLD, -1, gameMode, gameMode, false, false, false); Client.instance.javaConnection.processServerToClientPacket(playerRespawnS2CPacket); } @@ -45,4 +45,4 @@ public Class getPacketClass() { return RespawnPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityDataPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityDataPacketTranslator.java index de6735f..fc2105a 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityDataPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityDataPacketTranslator.java @@ -15,16 +15,16 @@ import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; public class SetEntityDataPacketTranslator extends PacketTranslator { + + // TODO: Set up an entity class system, like Geyser? + @Override public void translate(SetEntityDataPacket packet) { - - //TODO: Set up an entity class system, like Geyser? int id = (int) packet.getRuntimeEntityId(); if (TunnelMC.mc.world != null) { Entity entity = TunnelMC.mc.world.getEntityById(id); if (entity == null) { - //System.out.println("No entity found with ID " + id); return; } EntityDataMap metadata = packet.getMetadata(); @@ -47,6 +47,7 @@ public void translate(SetEntityDataPacket packet) { } else { entity.setPose(EntityPose.STANDING); } + // TODO: Climbing and swimming } EntityTrackerUpdateS2CPacket trackerUpdatePacket = new EntityTrackerUpdateS2CPacket(id, entity.getDataTracker(), true); @@ -59,4 +60,4 @@ public Class getPacketClass() { return SetEntityDataPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityMotionTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityMotionTranslator.java index 95cc2f5..310c4ac 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityMotionTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/SetEntityMotionTranslator.java @@ -13,7 +13,6 @@ public class SetEntityMotionTranslator extends PacketTranslator getPacketClass() { return SetEntityMotionPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/TakeItemEntityPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/TakeItemEntityPacketTranslator.java index 043b7bb..857a665 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/TakeItemEntityPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/entity/TakeItemEntityPacketTranslator.java @@ -10,10 +10,9 @@ public class TakeItemEntityPacketTranslator extends PacketTranslator javaContents = DefaultedList.ofSize(packet.getContents().size(), ItemStack.EMPTY); for (int i = 0; i < javaContainerSize; i++) { @@ -74,7 +74,6 @@ public void translate(InventoryContentPacket packet) { InventoryS2CPacket inventoryS2CPacket = new InventoryS2CPacket(syncId, javaContents); Client.instance.javaConnection.processServerToClientPacket(inventoryS2CPacket); - break; } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/inventory/InventorySlotPacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/inventory/InventorySlotPacketTranslator.java index 03a55fa..080f15b 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/inventory/InventorySlotPacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/inventory/InventorySlotPacketTranslator.java @@ -52,7 +52,7 @@ public Class getPacketClass() { @Override public boolean idleUntil() { - return TunnelMC.mc.player != null; + return TunnelMC.mc.player == null; } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/BlockEntityDataTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/BlockEntityDataTranslator.java index a857f15..15807bf 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/BlockEntityDataTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/BlockEntityDataTranslator.java @@ -10,6 +10,7 @@ import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; public class BlockEntityDataTranslator extends PacketTranslator { + @Override public void translate(BlockEntityDataPacket packet) { BlockEntityTranslator translator = BlockEntityRegistry.getBlockEntityTranslator(packet.getData()); @@ -25,4 +26,5 @@ public void translate(BlockEntityDataPacket packet) { public Class getPacketClass() { return BlockEntityDataPacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/ChunkRadiusUpdatedTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/ChunkRadiusUpdatedTranslator.java index c807f62..cb658fa 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/ChunkRadiusUpdatedTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/ChunkRadiusUpdatedTranslator.java @@ -18,4 +18,4 @@ public Class getPacketClass() { return ChunkRadiusUpdatedPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkDecoder.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkDecoder.java new file mode 100644 index 0000000..0f1bb12 --- /dev/null +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkDecoder.java @@ -0,0 +1,121 @@ +package me.THEREALWWEFAN231.tunnelmc.translator.packet.world; + +import com.nukkitx.nbt.NBTInputStream; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.util.stream.NetworkDataInputStream; +import com.nukkitx.network.VarInts; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import me.THEREALWWEFAN231.tunnelmc.nukkit.BitArray; +import me.THEREALWWEFAN231.tunnelmc.nukkit.BitArrayVersion; +import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.BlockPaletteTranslator; +import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.LegacyBlockPaletteManager; +import net.minecraft.block.BlockState; +import net.minecraft.world.chunk.ChunkSection; + +import java.io.IOException; + +/** + * The LevelChunkDecoder class contains methods on decoding every existing Bedrock sub chunk format. + */ +public class LevelChunkDecoder { + + /** + * Version eight is the newest chunk format introduced by Bedrock. + * It allows up to 256 layers for one sub chunk. + */ + public static void networkDecodeVersionEight(ByteBuf byteBuf, ChunkSection[] chunkSections, int sectionIndex, byte storageSize) { + for (int storageReadIndex = 0; storageReadIndex < storageSize; storageReadIndex++) { + byte paletteHeader = byteBuf.readByte(); + boolean isRuntime = (paletteHeader & 1) == 1; + int paletteVersion = (paletteHeader | 1) >> 1; + + BitArrayVersion bitArrayVersion = BitArrayVersion.get(paletteVersion, true); + + int maxBlocksInSection = 4096; + BitArray bitArray = bitArrayVersion.createPalette(maxBlocksInSection); + int wordsSize = bitArrayVersion.getWordsForSize(maxBlocksInSection); + + for (int wordIterationIndex = 0; wordIterationIndex < wordsSize; wordIterationIndex++) { + int word = byteBuf.readIntLE(); + bitArray.getWords()[wordIterationIndex] = word; + } + + int paletteSize = VarInts.readInt(byteBuf); + int[] sectionPalette = new int[paletteSize]; + NBTInputStream nbtStream = isRuntime ? null : new NBTInputStream(new NetworkDataInputStream(new ByteBufInputStream(byteBuf))); + for (int i = 0; i < paletteSize; i++) { + if (isRuntime) { + sectionPalette[i] = VarInts.readInt(byteBuf); + } else { + try { + NbtMapBuilder map = ((NbtMap) nbtStream.readTag()).toBuilder(); + map.replace("name", "minecraft:" + map.get("name").toString()); + + sectionPalette[i] = BlockPaletteTranslator.getBedrockBlockId(BlockPaletteTranslator.bedrockStateFromNBTMap(map.build())); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + if (storageReadIndex == 0) { + int index = 0; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + int paletteIndex = bitArray.get(index); + int mcbeBlockId = sectionPalette[paletteIndex]; + if (mcbeBlockId != BlockPaletteTranslator.AIR_BEDROCK_BLOCK_ID) { + + BlockState blockState = BlockPaletteTranslator.RUNTIME_ID_TO_BLOCK_STATE.get(mcbeBlockId); + + chunkSections[sectionIndex].setBlockState(x, y, z, blockState); + } + index++; + } + } + } + } + } + } + + /** + * Version one is the second newest chunk format by Bedrock. + * It is essentially the same as version eight, however there is only 1 layer per subchunk. + */ + public static void networkDecodeVersionOne(ByteBuf byteBuf, ChunkSection chunkSection) { + networkDecodeVersionEight(byteBuf, new ChunkSection[]{chunkSection}, 0, (byte) 1); + } + + /** + * Version zero is a chunk format used on PocketMine (3.0.0) servers. + * It is a legacy format that most third party servers use. + */ + public static void networkDecodeVersionZero(ByteBuf byteBuf, ChunkSection chunkSection) { + byte[] blockIds = new byte[4096]; + byteBuf.readBytes(blockIds); + + byte[] metaIds = new byte[2048]; + byteBuf.readBytes(metaIds); + + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + int index = (x << 8) + (z << 4) + y; + + int id = blockIds[index]; + int meta = metaIds[index >> 1] >> (index & 1) * 4 & 15; + + BlockState blockState = LegacyBlockPaletteManager.LEGACY_BLOCK_TO_JAVA_ID.get(id << 6 | meta); + + if (blockState != null) { + chunkSection.setBlockState(x, y, z, blockState); + } + } + } + } + } + +} diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkTranslator.java index f61fac1..fe5fd80 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelChunkTranslator.java @@ -2,11 +2,11 @@ import com.darkmagician6.eventapi.EventManager; import com.darkmagician6.eventapi.EventTarget; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NBTInputStream; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.util.stream.NetworkDataInputStream; -import com.nukkitx.network.VarInts; import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; @@ -14,14 +14,10 @@ import me.THEREALWWEFAN231.tunnelmc.TunnelMC; import me.THEREALWWEFAN231.tunnelmc.bedrockconnection.Client; import me.THEREALWWEFAN231.tunnelmc.events.EventPlayerTick; -import me.THEREALWWEFAN231.tunnelmc.nukkit.BitArray; -import me.THEREALWWEFAN231.tunnelmc.nukkit.BitArrayVersion; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; -import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.BlockPaletteTranslator; -import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.LegacyBlockPaletteManager; -import net.minecraft.block.BlockState; import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; import net.minecraft.util.collection.IndexedIterable; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.registry.DynamicRegistryManager; @@ -33,10 +29,16 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +/** + * For more information, check out the following gist: + * https://gist.github.com/dktapps/8a4f23d2bf32ea7091ef14e4aac46170 + */ public class LevelChunkTranslator extends PacketTranslator { - private static final IndexedIterable BIOME_REGISTRY = DynamicRegistryManager.create().get(Registry.BIOME_KEY); + + private static final IndexedIterable BIOMES_REGISTRY = DynamicRegistryManager.create().get(Registry.BIOME_KEY); private final List chunksOutOfRenderDistance = new ArrayList<>(); @@ -44,48 +46,13 @@ public LevelChunkTranslator() { EventManager.register(this); } - //TODO: block entities, biomes, and probably lighting - @Override public void translate(LevelChunkPacket packet) { - /* - * So id like to make a note on this, so i dont forget how this works, and or so someone else knows how this works - * a chunk is made up of 16 vertical sections, 16 blocks tall each, meaning 16(blocks) * 16(vertical sections) = 256(the build height) - * subChunksLength is equal the highest section(remember there is only 16 sections), so if the chunk only has a few blocks that are - * y <= 15(maybe 16?) subChunksLength will equal 1, because only 1 section is being used. another example would be, say the chunk is - * completely empty, except there is 1 stone block at y = 50, there will be 4 sections, 16*3=48(not big enough), 16*4=64(big enough, but not too big) - * - * the data bytes in the packet hold all the chunk information, first we have to iterate though all the sections(explained above) - * we then read a byte(im not fully sure what its used for, yet, but geyser names it "CHUNK_SECTION_VERSION"), then we read another byte - * "storageSize" which appears to always equal 2, from looking at nukkit and stuff, it appears the server sends 2 chunk layers? im not even fully sure - * what that means, but it appears the second one is always empty. we then iterate though all the "storages"(like i said always 2?) - * we then read a byte which is the "paletteHeader"? from that we get the "paletteVersion" from that we can create a "BitArray" - * which is like hashed and or compressed data?(im not even fully sure). from the bit array we created, we can then get the chunk sections' "words" - * by iterating though the max "word" count in the BitArray we created and reading a 32 bit integer which has compressed data? basically im pretty sure - * the "words" in a BitArray are compressed, so if input the 32 bit integer we read into the BitArrays' "words" we can use the BitArray to get the real - * uncompressed data(ill explain what these "words" are in a minute). after we read all the words we then read a VarInt which has the size of the block palette - * - * What is a block palette? each section in a chunk(remember theres a max of 16), has a block palette which contains data about the blocks in the section - * for example, index0=air, index1=stone, index2=diamond_ore, that is our block palette, these are the only blocks used in this section of a chunk. - * thats an example, the block palettes' values(air, stone, diamond_ore) aren't actual strings they are integers, the blocks mcbe "runtimeId". - * - * So after we get the size of the block palette(x) we then read x VarInts to get the palette information, so now we have an int array which are be referred - * to by index to get the runtime id of any block in the section. We then have to do that, we iterate though the x, then z, then y coordinate of the chunk section - * we use the BitArray(which has "words") the get the "decompressed" block palette index, once we have this, we refer to the block palette, and get the mcbe runtimeId - * or the specific xyz coordinate, which we then translate to java. - * - * I know this is probably confusing, the code is probably more clear then this, but i tried. - * - * TLDR: we read some information about a chunk section, which has a key and value, the value being a mcbe block runtimeId, we go though all block positions - * for the chunks' section(that we are currently iterating). from that we get the key, which of course gives us the value(mcbe block runtimeId) - * - */ - int chunkX = packet.getChunkX(); int chunkZ = packet.getChunkZ(); if (TunnelMC.mc.player != null) { - if (!this.isChunkInRenderDistance(chunkX, chunkZ)) { + if (this.isChunkInRenderDistance(chunkX, chunkZ)) { this.chunksOutOfRenderDistance.add(packet); return; } @@ -100,87 +67,41 @@ public void translate(LevelChunkPacket packet) { chunkSections[sectionIndex] = new ChunkSection(sectionIndex); int chunkVersion = byteBuf.readByte(); if (chunkVersion != 1 && chunkVersion != 8) { - manage0VersionChunk(byteBuf, chunkSections[sectionIndex]); + System.out.println("Decoding a version zero chunk..."); + LevelChunkDecoder.networkDecodeVersionZero(byteBuf, chunkSections[sectionIndex]); continue; } - - byte storageSize = chunkVersion == 1 ? 1 : byteBuf.readByte(); - - for (int storageReadIndex = 0; storageReadIndex < storageSize; storageReadIndex++) { - byte paletteHeader = byteBuf.readByte(); - boolean isRuntime = (paletteHeader & 1) == 1; - int paletteVersion = (paletteHeader | 1) >> 1; - - BitArrayVersion bitArrayVersion = BitArrayVersion.get(paletteVersion, true); - - int maxBlocksInSection = 4096; // 16*16*16 - BitArray bitArray = bitArrayVersion.createPalette(maxBlocksInSection); - int wordsSize = bitArrayVersion.getWordsForSize(maxBlocksInSection); - - for (int wordIterationIndex = 0; wordIterationIndex < wordsSize; wordIterationIndex++) { - int word = byteBuf.readIntLE(); - bitArray.getWords()[wordIterationIndex] = word; - } - - int paletteSize = VarInts.readInt(byteBuf); - int[] sectionPalette = new int[paletteSize]; - NBTInputStream nbtStream = isRuntime ? null : new NBTInputStream(new NetworkDataInputStream(new ByteBufInputStream(byteBuf))); - for (int i = 0; i < paletteSize; i++) { - if (isRuntime) { - sectionPalette[i] = VarInts.readInt(byteBuf); - } else { - try { - NbtMapBuilder map = ((NbtMap) nbtStream.readTag()).toBuilder(); - // For some reason, persistent chunks don't include the "minecraft:" that should be used in state names. - map.replace("name", "minecraft:" + map.get("name").toString()); - sectionPalette[i] = BlockPaletteTranslator.getBedrockBlockId(BlockPaletteTranslator.bedrockStateFromNBTMap(map.build())); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - if (storageReadIndex == 0) { - int index = 0; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - int paletteIndex = bitArray.get(index); - int mcbeBlockId = sectionPalette[paletteIndex]; - if (mcbeBlockId != BlockPaletteTranslator.AIR_BEDROCK_BLOCK_ID) { - - BlockState blockState = BlockPaletteTranslator.RUNTIME_ID_TO_BLOCK_STATE.get(mcbeBlockId); - - chunkSections[sectionIndex].setBlockState(x, y, z, blockState); - } - index++; - } - } - } - } + if (chunkVersion == 1) { + System.out.println("Decoding a version one chunk..."); + LevelChunkDecoder.networkDecodeVersionOne(byteBuf, chunkSections[sectionIndex]); + continue; } + + System.out.println("Decoding a version eight chunk..."); + LevelChunkDecoder.networkDecodeVersionEight(byteBuf, chunkSections, sectionIndex, byteBuf.readByte()); } byte[] bedrockBiomes = new byte[256]; byteBuf.readBytes(bedrockBiomes); + // TODO: Block entities + int[] javaBiomes = new int[1024]; - int javaBiomeCount = 0; + int javaBiomesCount = 0; for (byte bedrockBiome : bedrockBiomes) { byte desiredBiome = bedrockBiome; - if (BIOME_REGISTRY.get(desiredBiome) == null) { - // Invalid biome that spams the console - // I got -98 so it could also be an encoding issue + + if (BIOMES_REGISTRY.get(desiredBiome) == null) { desiredBiome = 1; } - javaBiomes[javaBiomeCount++] = desiredBiome; - // convert 256 to 1024 - javaBiomes[javaBiomeCount++] = desiredBiome; - javaBiomes[javaBiomeCount++] = desiredBiome; - javaBiomes[javaBiomeCount++] = desiredBiome; + + javaBiomes[javaBiomesCount++] = desiredBiome; + javaBiomes[javaBiomesCount++] = desiredBiome; + javaBiomes[javaBiomesCount++] = desiredBiome; + javaBiomes[javaBiomesCount++] = desiredBiome; } - BiomeArray biomeArray = new BiomeArray(BIOME_REGISTRY, javaBiomes); + BiomeArray biomeArray = new BiomeArray(BIOMES_REGISTRY, javaBiomes); WorldChunk worldChunk = new WorldChunk(null, new ChunkPos(chunkX, chunkZ), biomeArray); for (int i = 0; i < worldChunk.getSectionArray().length; i++) { @@ -191,56 +112,32 @@ public void translate(LevelChunkPacket packet) { Client.instance.javaConnection.processServerToClientPacket(chunkDeltaUpdateS2CPacket); } - /** - * Used for PocketMine. - */ - private void manage0VersionChunk(ByteBuf byteBuf, ChunkSection chunkSection) { - byte[] blockIds = new byte[4096]; - byteBuf.readBytes(blockIds); - - byte[] metaIds = new byte[2048]; - byteBuf.readBytes(metaIds); - - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int idx = (x << 8) + (z << 4) + y; - int id = blockIds[idx]; - int meta = metaIds[idx >> 1] >> (idx & 1) * 4 & 15; - - BlockState blockState = LegacyBlockPaletteManager.LEGACY_BLOCK_TO_JAVA_ID.get(id << 6 | meta); - - if (blockState != null) { - chunkSection.setBlockState(x, y, z, blockState); - } - } - } - } - } - @Override public Class getPacketClass() { return LevelChunkPacket.class; } public boolean isChunkInRenderDistance(int chunkX, int chunkZ) { + if (TunnelMC.mc.player == null) { + return false; + } int playerChunkX = MathHelper.floor(TunnelMC.mc.player.getX()) >> 4; int playerChunkZ = MathHelper.floor(TunnelMC.mc.player.getZ()) >> 4; - return Math.abs(chunkX - playerChunkX) <= TunnelMC.mc.options.viewDistance && Math.abs(chunkZ - playerChunkZ) <= TunnelMC.mc.options.viewDistance; + return Math.abs(chunkX - playerChunkX) > TunnelMC.mc.options.viewDistance || Math.abs(chunkZ - playerChunkZ) > TunnelMC.mc.options.viewDistance; } @EventTarget public void onEvent(EventPlayerTick event) { - // this needs some work, general chunk loading needs some work as well - for(int i = 0; i < this.chunksOutOfRenderDistance.size(); i++) { // could use an iterator, but that's no fun? - LevelChunkPacket levelChunkPacket = this.chunksOutOfRenderDistance.get(i); - if (!this.isChunkInRenderDistance(levelChunkPacket.getChunkX(), levelChunkPacket.getChunkZ())) { + // This needs some work, general chunk loading needs some work as well. + Iterator iterator = chunksOutOfRenderDistance.iterator(); + while (iterator.hasNext()) { + LevelChunkPacket chunk = iterator.next(); + if (this.isChunkInRenderDistance(chunk.getChunkX(), chunk.getChunkZ())) { continue; } - this.translate(levelChunkPacket); - this.chunksOutOfRenderDistance.remove(i); - i--; + translate(chunk); + iterator.remove(); } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelEventTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelEventTranslator.java index ff226ab..3cc6e58 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelEventTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelEventTranslator.java @@ -26,13 +26,14 @@ import java.util.SortedSet; public class LevelEventTranslator extends PacketTranslator { + public static final Object2ObjectMap BLOCK_BREAKING_INFOS = new Object2ObjectOpenHashMap<>(); public static final LongSet TO_REMOVE = new LongOpenHashSet(); private final Random random = new Random(); @Override public void translate(LevelEventPacket packet) { - if (MinecraftClient.getInstance().world == null) { + if (MinecraftClient.getInstance().world == null || MinecraftClient.getInstance().interactionManager == null) { return; } @@ -57,7 +58,7 @@ public void translate(LevelEventPacket packet) { break; } case BLOCK_STOP_BREAK: { - if (packet.getPosition().equals(Vector3f.ZERO)) { // Apparently... + if (packet.getPosition().equals(Vector3f.ZERO)) { if (BLOCK_BREAKING_INFOS.containsKey(packet.getPosition().toInt())) { long key = ((IMixinClientPlayerInteractionManager) MinecraftClient.getInstance().interactionManager).getCurrentBreakingPos().asLong(); TO_REMOVE.add(key); @@ -139,4 +140,5 @@ public BlockBreakingWrapper(int length, BlockBreakingInfo blockBreakingInfo) { this.blockBreakingInfo = blockBreakingInfo; } } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEvent2Translator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEvent2Translator.java index e5b941a..9174377 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEvent2Translator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEvent2Translator.java @@ -15,4 +15,5 @@ public void translate(LevelSoundEvent2Packet packet) { public Class getPacketClass() { return LevelSoundEvent2Packet.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEventTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEventTranslator.java index 610edc7..45e9c4f 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEventTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/LevelSoundEventTranslator.java @@ -1,5 +1,6 @@ package me.THEREALWWEFAN231.tunnelmc.translator.packet.world; +import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import me.THEREALWWEFAN231.tunnelmc.translator.PacketTranslator; import me.THEREALWWEFAN231.tunnelmc.translator.blockstate.BlockPaletteTranslator; @@ -12,17 +13,16 @@ import net.minecraft.util.math.BlockPos; public class LevelSoundEventTranslator extends PacketTranslator { + @Override public void translate(LevelSoundEventPacket packet) { - switch (packet.getSound()) { - case HIT: - BlockPos pos = PositionUtil.toBlockPos(packet.getPosition()); - BlockState blockState = BlockPaletteTranslator.RUNTIME_ID_TO_BLOCK_STATE.get(packet.getExtraData()); - BlockSoundGroup blockSoundGroup = blockState.getSoundGroup(); - MinecraftClient.getInstance().getSoundManager().play( - new PositionedSoundInstance(blockSoundGroup.getHitSound(), SoundCategory.BLOCKS, - (blockSoundGroup.getVolume() + 1.0F) / 8.0F, blockSoundGroup.getPitch() * 0.5F, pos)); - break; + if (packet.getSound() == SoundEvent.HIT) { + BlockPos pos = PositionUtil.toBlockPos(packet.getPosition()); + BlockState blockState = BlockPaletteTranslator.RUNTIME_ID_TO_BLOCK_STATE.get(packet.getExtraData()); + BlockSoundGroup blockSoundGroup = blockState.getSoundGroup(); + MinecraftClient.getInstance().getSoundManager().play( + new PositionedSoundInstance(blockSoundGroup.getHitSound(), SoundCategory.BLOCKS, + (blockSoundGroup.getVolume() + 1.0F) / 8.0F, blockSoundGroup.getPitch() * 0.5F, pos)); } } @@ -30,4 +30,5 @@ public void translate(LevelSoundEventPacket packet) { public Class getPacketClass() { return LevelSoundEventPacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/NetworkChunkPublisherUpdateTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/NetworkChunkPublisherUpdateTranslator.java index db1cf42..1a199db 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/NetworkChunkPublisherUpdateTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/NetworkChunkPublisherUpdateTranslator.java @@ -19,4 +19,5 @@ public void translate(NetworkChunkPublisherUpdatePacket packet) { public Class getPacketClass() { return NetworkChunkPublisherUpdatePacket.class; } -} + +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/SetTimePacketTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/SetTimePacketTranslator.java index 2f49b9a..469639c 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/SetTimePacketTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/SetTimePacketTranslator.java @@ -22,7 +22,7 @@ public Class getPacketClass() { @Override public boolean idleUntil() { - return TunnelMC.mc.world != null; + return TunnelMC.mc.world == null; } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/UpdateBlockTranslator.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/UpdateBlockTranslator.java index 062e196..ddd6f29 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/UpdateBlockTranslator.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/translator/packet/world/UpdateBlockTranslator.java @@ -13,7 +13,7 @@ public class UpdateBlockTranslator extends PacketTranslator { - //TODO: probably want to check out flags + //TODO: Probably want to check out flags. @Override public void translate(UpdateBlockPacket packet) { @@ -25,7 +25,7 @@ public void translate(UpdateBlockPacket packet) { Client.instance.javaConnection.processServerToClientPacket(blockUpdateS2CPacket); } else if (packet.getDataLayer() == 1) { - // Set waterlogged state of existing block + // Set waterlogged state of existing block. BlockState blockState = MinecraftClient.getInstance().world.getBlockState(blockPos); BlockState newBlockState; if (blockState.isAir()) { @@ -52,4 +52,4 @@ public Class getPacketClass() { return UpdateBlockPacket.class; } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/FileManagement.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/FileManagement.java index 7dfe00b..8ae773c 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/FileManagement.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/FileManagement.java @@ -1,23 +1,19 @@ package me.THEREALWWEFAN231.tunnelmc.utils; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStream; -import java.nio.file.Files; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + public class FileManagement { - public Gson normalGson = new GsonBuilder().disableHtmlEscaping().create(); - public Gson formattedGson = new GsonBuilder().setPrettyPrinting().create(); + public Gson gJson = new GsonBuilder().disableHtmlEscaping().create(); public JsonParser jsonParser = new JsonParser(); public String getTextFromInputStream(InputStream inputStream) throws Exception { - //this is "super fast" ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; @@ -25,30 +21,25 @@ public String getTextFromInputStream(InputStream inputStream) throws Exception { byteArrayOutputStream.write(buffer, 0, length); } - byteArrayOutputStream.close();//says it does nothing, but who cares + byteArrayOutputStream.close(); inputStream.close(); return byteArrayOutputStream.toString("UTF-8"); } - public String getTextFromFile(File file) throws Exception { - return new String(Files.readAllBytes(file.toPath()));//this is "super fast" - } - public JsonObject getJsonObjectFromResource(String resourceName) { - InputStream inputStream = FileManagement.class.getClassLoader().getResourceAsStream(resourceName); + if (inputStream == null) { + System.out.println("Resource \"" + resourceName + "\" does not exist!"); + return null; + } - JsonObject jsonObject = null; try { - jsonObject = this.jsonParser.parse(this.getTextFromInputStream(inputStream)).getAsJsonObject(); + return this.jsonParser.parse(this.getTextFromInputStream(inputStream)).getAsJsonObject(); } catch (Exception e) { - System.out.println("Failed to read \"" + resourceName + "\""); + System.out.println("Failed to read \"" + resourceName + "\": " + e.getMessage()); return null; } - - return jsonObject; - } -} +} \ No newline at end of file diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ItemDataUtils.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ItemDataUtils.java index 5a3a38d..fb15b6b 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ItemDataUtils.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ItemDataUtils.java @@ -5,10 +5,7 @@ public class ItemDataUtils { public static ItemData copyWithCount(ItemData toCopy, int newCount) { - //probably should find a copy to copy the tag? - ItemData copied = toCopy.toBuilder().count(newCount).build(); - - return copied; + return toCopy.toBuilder().count(newCount).build(); } } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/PositionUtil.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/PositionUtil.java index a60ae7f..b071bd9 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/PositionUtil.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/PositionUtil.java @@ -5,6 +5,7 @@ import net.minecraft.util.math.BlockPos; public class PositionUtil { + public static BlockPos toBlockPos(Vector3i vector) { return new BlockPos(vector.getX(), vector.getY(), vector.getZ()); } @@ -13,6 +14,7 @@ public static BlockPos toBlockPos(Vector3f vector) { return new BlockPos(vector.getX(), vector.getY(), vector.getZ()); } + @SuppressWarnings("unused") public static Vector3i toBedrockVector3i(BlockPos blockPos) { return Vector3i.from(blockPos.getX(), blockPos.getY(), blockPos.getZ()); } @@ -20,4 +22,5 @@ public static Vector3i toBedrockVector3i(BlockPos blockPos) { public static Vector3f toBedrockVector3f(BlockPos blockPos) { return Vector3f.from(blockPos.getX(), blockPos.getY(), blockPos.getZ()); } + } diff --git a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ScaffoldPlace.java b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ScaffoldPlace.java index ad387d0..0f2a86d 100644 --- a/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ScaffoldPlace.java +++ b/src/main/java/me/THEREALWWEFAN231/tunnelmc/utils/ScaffoldPlace.java @@ -12,10 +12,17 @@ public class ScaffoldPlace { - //so this isn't exactly like bedrock, but for now it gets the job down, but we need to make it so the players cant break blocks, only place(or add a option for this at a later time), which would call for a whole new technique + /** + * This isn't exactly like bedrock, but it gets the job done for now. + * Later on, we need to make that there's an option to toggle both breaking and placing. + */ public static void setRaycastResult() { - if (TunnelMC.mc.crosshairTarget.getType() == HitResult.Type.MISS && MathHelper.wrapDegrees(TunnelMC.mc.player.pitch) > 50) { + if (TunnelMC.mc.world == null || TunnelMC.mc.crosshairTarget == null || TunnelMC.mc.player == null) { + System.out.println("Attempted to set ray cast result with null required fields!"); + return; + } + if (TunnelMC.mc.crosshairTarget.getType() == HitResult.Type.MISS && MathHelper.wrapDegrees(TunnelMC.mc.player.pitch) > 50) { BlockPos belowThePlayer = TunnelMC.mc.player.getBlockPos().down(); Block blockUnderThePlayer = TunnelMC.mc.world.getBlockState(belowThePlayer).getBlock(); if (blockUnderThePlayer instanceof AirBlock) { @@ -23,7 +30,6 @@ public static void setRaycastResult() { } Direction direction = Direction.fromRotation(TunnelMC.mc.player.yaw); - //+0.5 for the middle of the block, because why not TunnelMC.mc.crosshairTarget = new BlockHitResult(new Vec3d(belowThePlayer.getX() + 0.5, belowThePlayer.getY() + 0.5, belowThePlayer.getZ() + 0.5), direction, belowThePlayer, false); } } diff --git a/src/main/resources/tunnelmc/blockpalette.nbt b/src/main/resources/tunnel/block_palette.nbt similarity index 100% rename from src/main/resources/tunnelmc/blockpalette.nbt rename to src/main/resources/tunnel/block_palette.nbt diff --git a/src/main/resources/tunnelmc/entity override translations.json b/src/main/resources/tunnel/entity_override_translations.json similarity index 100% rename from src/main/resources/tunnelmc/entity override translations.json rename to src/main/resources/tunnel/entity_override_translations.json diff --git a/src/main/resources/tunnelmc/runtime_block_states.dat b/src/main/resources/tunnel/runtime_block_states.dat similarity index 100% rename from src/main/resources/tunnelmc/runtime_block_states.dat rename to src/main/resources/tunnel/runtime_block_states.dat