diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 2dac0f4c6..8d0185cc8 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -31,7 +31,7 @@ object Versions { const val gsonVersion = "2.3.1" // Provided by Spigot 1.8.8 const val nbtVersion = "2.1.0" const val websocketVersion = "1.5.1" - const val protocolVersion = "0bd459f" + const val protocolVersion = "f0feacd" const val raknetVersion = "1.6.28-20220125.214016-6" const val mcauthlibVersion = "d9d773e" const val mcprotocollibversion = "9f78bd5" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 5049c93ab..b0325e33c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // Network libraries implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) - api("com.github.CloudburstMC.Protocol", "bedrock-v544", Versions.protocolVersion) { + api("com.github.CloudburstMC.Protocol", "bedrock-v553", Versions.protocolVersion) { exclude("com.nukkitx.network", "raknet") exclude("com.nukkitx", "nbt") } diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index 4ed077a7b..bf655740f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.network; import com.nukkitx.protocol.bedrock.BedrockPong; import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; import com.nukkitx.protocol.bedrock.BedrockServerSession; +import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultEventLoopGroup; @@ -171,7 +172,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public void onSessionCreation(@Nonnull BedrockServerSession bedrockServerSession) { try { - bedrockServerSession.setPacketCodec(GameProtocol.DEFAULT_BEDROCK_CODEC); + bedrockServerSession.setPacketCodec(Bedrock_v553.V553_CODEC); // Has the RequestNetworkSettingsPacket bedrockServerSession.setLogging(true); bedrockServerSession.setCompressionLevel(geyser.getConfig().getBedrock().getCompressionLevel()); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(geyser, new GeyserSession(geyser, bedrockServerSession, eventLoopGroup.next()))); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 006f40ace..dde0b0c04 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v527.Bedrock_v527; import com.nukkitx.protocol.bedrock.v534.Bedrock_v534; import com.nukkitx.protocol.bedrock.v544.Bedrock_v544; +import com.nukkitx.protocol.bedrock.v553.Bedrock_v553; import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; @@ -71,6 +72,7 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.21/1.19.22") .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v553.V553_CODEC); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index b0b707ee0..7edf560e8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -856,4 +856,11 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public boolean handle(FilterTextPacket packet) { return defaultHandler(packet); } + + // 1.19.30 new packet + + @Override + public boolean handle(RequestNetworkSettingsPacket packet) { + return defaultHandler(packet); + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 5a8fa3013..286a2eb9b 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.network; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.data.ExperimentData; +import com.nukkitx.protocol.bedrock.data.PacketCompressionAlgorithm; import com.nukkitx.protocol.bedrock.data.ResourcePackType; import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.GeyserImpl; @@ -61,6 +62,20 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return translateAndDefault(packet); } + @Override + public boolean handle(RequestNetworkSettingsPacket packet) { + // New since 1.19.30 - sent before login packet + PacketCompressionAlgorithm algorithm = PacketCompressionAlgorithm.ZLIB; + + NetworkSettingsPacket responsePacket = new NetworkSettingsPacket(); + responsePacket.setCompressionAlgorithm(algorithm); + responsePacket.setCompressionThreshold(512); + session.sendUpstreamPacketImmediately(responsePacket); + + session.getUpstream().getSession().setCompression(algorithm); + return true; + } + @Override public boolean handle(LoginPacket loginPacket) { if (geyser.isShuttingDown()) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index f0a215f2a..920ada5fb 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -33,6 +33,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -171,7 +172,7 @@ public class RecipeRegistryPopulator { /* Convert end */ return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } List inputs = new ObjectArrayList<>(); for (JsonNode entry : node.get("inputs")) { @@ -191,10 +192,10 @@ public class RecipeRegistryPopulator { if (type == 5) { // Shulker box return CraftingData.fromShulkerBox(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } return CraftingData.fromShapeless(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, netId); + inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId); } private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) { diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 2660f54b1..02940e00c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -62,7 +62,8 @@ public final class SessionManager { } public void removeSession(GeyserSession session) { - if (sessions.remove(session.getPlayerEntity().getUuid()) == null) { + UUID uuid = session.getPlayerEntity().getUuid(); + if (uuid == null || sessions.remove(uuid) == null) { // Connection was likely pending pendingSessions.remove(session); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 4c72a359a..d11caf601 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -34,9 +34,10 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeDa import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; +import com.nukkitx.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -99,8 +100,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); + private ItemDescriptorWithCount[][] combinations(GeyserSession session, Ingredient[] ingredients) { + Map, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { - squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new IntOpenHashSet()).add(i); + squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i); continue; } Ingredient ingredient = ingredients[i]; - Map> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(item -> ItemTranslator.translateToBedrock(session, item)) - .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); - Set optionSet = new HashSet<>(groupedByIds.size()); - for (Map.Entry> entry : groupedByIds.entrySet()) { + Map> groupedByIds = Arrays.stream(ingredient.getOptions()) + .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item))) + .collect(Collectors.groupingBy(item -> new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount()))); + Set optionSet = new HashSet<>(groupedByIds.size()); + for (Map.Entry> entry : groupedByIds.entrySet()) { if (entry.getValue().size() > 1) { GroupedItem groupedItem = entry.getKey(); int idCount = 0; @@ -234,42 +236,38 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new IntOpenHashSet()).add(i); } int totalCombinations = 1; - for (Set optionSet : squashedOptions.keySet()) { + for (Set optionSet : squashedOptions.keySet()) { totalCombinations *= optionSet.size(); } if (totalCombinations > 500) { - ItemData[] translatedItems = new ItemData[ingredients.length]; + ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length]; for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length > 0) { - translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]); + translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0])); } else { - translatedItems[i] = ItemData.AIR; + translatedItems[i] = ItemDescriptorWithCount.EMPTY; } } - return new ItemData[][]{translatedItems}; + return new ItemDescriptorWithCount[][]{translatedItems}; } - List> sortedSets = new ArrayList<>(squashedOptions.keySet()); + List> sortedSets = new ArrayList<>(squashedOptions.keySet()); sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder())); - ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length]; + ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length]; int x = 1; - for (Set set : sortedSets) { + for (Set set : sortedSets) { IntSet slotSet = squashedOptions.get(set); int i = 0; - for (ItemData item : set) { + for (ItemDescriptorWithCount item : set) { for (int j = 0; j < totalCombinations / set.size(); j++) { final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x); for (int slot : slotSet) { @@ -288,6 +286,5 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator