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 3e5b87e2c..e23299bfa 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -28,8 +28,14 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +import org.cloudburstmc.protocol.bedrock.codec.v557.Bedrock_v557; +import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; +import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; +import org.geysermc.geyser.session.GeyserSession; import java.util.ArrayList; import java.util.List; @@ -58,6 +64,17 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.CODEC.toBuilder() + .minecraftVersion("1.19.40/1.19.41") + .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.CODEC.toBuilder() + .minecraftVersion("1.19.50/1.19.51") + .build()); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v568.CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v575.CODEC.toBuilder() + .minecraftVersion("1.19.70/1.19.71/1.19.73") + .build()); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() .minecraftVersion("1.19.80/1.19.81") .build()); @@ -77,6 +94,20 @@ public final class GameProtocol { return null; } + /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ + + public static boolean supports1_19_50(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v560.CODEC.getProtocolVersion(); + } + + public static boolean supports1_19_60(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v567.CODEC.getProtocolVersion(); + } + + public static boolean supports1_19_80(GeyserSession session) { + return session.getUpstream().getProtocolVersion() >= Bedrock_v582.CODEC.getProtocolVersion(); + } + /** * Gets the {@link PacketCodec} for Minecraft: Java Edition. * 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 89a82fbbd..f373cd25d 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,8 @@ package org.geysermc.geyser.network; import io.netty.buffer.Unpooled; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568; import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; @@ -171,6 +173,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return PacketSignal.HANDLED; } + // Hack for... whatever this is + if (loginPacket.getProtocolVersion() == Bedrock_v567.CODEC.getProtocolVersion() && !session.getClientData().getGameVersion().equals("1.19.60")) { + session.getUpstream().getSession().setCodec(Bedrock_v568.CODEC); + } + PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); session.sendUpstreamPacket(playStatus); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 713665b97..d071bfc90 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -32,6 +32,10 @@ import com.google.common.collect.Interner; import com.google.common.collect.Interners; import it.unimi.dsi.fastutil.objects.*; import org.cloudburstmc.nbt.*; +import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; +import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; +import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -78,6 +82,10 @@ public final class BlockRegistryPopulator { }; BiFunction emptyMapper = (bedrockIdentifier, statesBuilder) -> null; ImmutableMap, BiFunction> blockMappers = ImmutableMap., BiFunction>builder() + .put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper) + .put(ObjectIntPair.of("1_19_50", Bedrock_v560.CODEC.getProtocolVersion()), emptyMapper) + .put(ObjectIntPair.of("1_19_60", Bedrock_v567.CODEC.getProtocolVersion()), emptyMapper) + .put(ObjectIntPair.of("1_19_70", Bedrock_v575.CODEC.getProtocolVersion()), woolMapper) .put(ObjectIntPair.of("1_19_80", Bedrock_v582.CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> { String identifier = woolMapper.apply(bedrockIdentifier, statesBuilder); if (identifier != null) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 04c58165e..1713f263d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -37,6 +37,10 @@ import it.unimi.dsi.fastutil.objects.*; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; +import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; +import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.codec.v582.Bedrock_v582; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; @@ -70,7 +74,17 @@ public class ItemRegistryPopulator { } public static void populate() { + Map manualFallback = new HashMap<>(); + manualFallback.put(Items.ENDER_DRAGON_SPAWN_EGG, "minecraft:enderman_spawn_egg"); + manualFallback.put(Items.WITHER_SPAWN_EGG, "minecraft:wither_skeleton_spawn_egg"); + manualFallback.put(Items.SNOW_GOLEM_SPAWN_EGG, "minecraft:polar_bear_spawn_egg"); + manualFallback.put(Items.IRON_GOLEM_SPAWN_EGG, "minecraft:villager_spawn_egg"); + Map paletteVersions = new Object2ObjectOpenHashMap<>(); + paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.CODEC.getProtocolVersion(), manualFallback)); + paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.CODEC.getProtocolVersion(), manualFallback)); + paletteVersions.put("1_19_60", new PaletteVersion(Bedrock_v567.CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_70", new PaletteVersion(Bedrock_v575.CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_80", new PaletteVersion(Bedrock_v582.CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -168,6 +182,11 @@ public class ItemRegistryPopulator { Set javaOnlyItems = new ObjectOpenHashSet<>(); Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK, Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE); + // these spawn eggs exist in 1.19.60+; + if (palette.getValue().protocolVersion() < Bedrock_v567.CODEC.getProtocolVersion()) { + Collections.addAll(javaOnlyItems, Items.IRON_GOLEM_SPAWN_EGG, Items.SNOW_GOLEM_SPAWN_EGG, + Items.WITHER_SPAWN_EGG, Items.ENDER_DRAGON_SPAWN_EGG); + } javaOnlyItems.add(Items.DECORATED_POT); if (!customItemsAllowed) { javaOnlyItems.add(Items.FURNACE_MINECART); @@ -199,17 +218,20 @@ public class ItemRegistryPopulator { } String bedrockIdentifier; - if (mappingItem.getBedrockIdentifier().equals("minecraft:wool")) { + // 1.19.70+ + if (palette.getValue().protocolVersion() >= Bedrock_v575.CODEC.getProtocolVersion() && mappingItem.getBedrockIdentifier().equals("minecraft:wool")) { bedrockIdentifier = javaItem.javaIdentifier(); } else { bedrockIdentifier = mappingItem.getBedrockIdentifier(); } //1.19.80+ - if (mappingItem.getBedrockIdentifier().equals("minecraft:log") || - mappingItem.getBedrockIdentifier().equals("minecraft:log2") || - mappingItem.getBedrockIdentifier().equals("minecraft:fence")) { - bedrockIdentifier = javaItem.javaIdentifier(); + if (palette.getValue().protocolVersion >= Bedrock_v582.CODEC.getProtocolVersion()) { + if (mappingItem.getBedrockIdentifier().equals("minecraft:log") || + mappingItem.getBedrockIdentifier().equals("minecraft:log2") || + mappingItem.getBedrockIdentifier().equals("minecraft:fence")) { + bedrockIdentifier = javaItem.javaIdentifier(); + } } ItemDefinition definition = definitions.get(bedrockIdentifier); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 691ca3c88..40444ab72 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -42,6 +42,7 @@ import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.BoundingBox; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; @@ -621,6 +622,10 @@ public class PistonBlockEntity { Vector3i movement = getMovement(); attachedBlocks.forEach((blockPos, javaId) -> { blockPos = blockPos.add(movement); + if (!GameProtocol.supports1_19_50(session)) { + // Send a final block entity packet to detach blocks for clients older than 1.19.50 + BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(blockPos, javaId, Direction.DOWN.getUnitVector()), blockPos); + } // Don't place blocks that collide with the player if (!SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), session.getCollisionManager().getPlayerBoundingBox())) { ChunkUtils.updateBlock(session, javaId, blockPos); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index 0e58917c7..a26bba618 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.Serverb import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -44,9 +45,15 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator