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 42cce607b..a03a36ad2 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 org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; +import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; @@ -46,7 +47,7 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v630.CODEC; + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v649.CODEC; /** * A list of all supported Bedrock versions that can join Geyser @@ -63,9 +64,12 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v622.CODEC.toBuilder() .minecraftVersion("1.20.40/1.20.41") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v630.CODEC.toBuilder() .minecraftVersion("1.20.50/1.20.51") .build()); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.20.60/1.20.61") + .build()); } /** @@ -88,6 +92,10 @@ public final class GameProtocol { return session.getUpstream().getProtocolVersion() < Bedrock_v630.CODEC.getProtocolVersion(); } + public static boolean is1_20_60orHigher(int protocolVersion) { + return protocolVersion >= Bedrock_v649.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 7a22b8a42..df5eb36f7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -33,6 +33,9 @@ import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; +import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStrategy; +import org.cloudburstmc.protocol.bedrock.netty.codec.compression.SimpleCompressionStrategy; +import org.cloudburstmc.protocol.bedrock.netty.codec.compression.ZlibCompression; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.LoginPacket; import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket; @@ -48,6 +51,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket; import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.cloudburstmc.protocol.common.PacketSignal; +import org.cloudburstmc.protocol.common.util.Zlib; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.network.AuthType; @@ -77,11 +81,16 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { private boolean networkSettingsRequested = false; private final Deque packsToSent = new ArrayDeque<>(); + private final CompressionStrategy compressionStrategy; private SessionLoadResourcePacksEventImpl resourcePackLoadEvent; public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) { super(geyser, session); + + ZlibCompression compression = new ZlibCompression(Zlib.RAW); + compression.setLevel(this.geyser.getConfig().getBedrock().getCompressionLevel()); + this.compressionStrategy = new SimpleCompressionStrategy(compression); } private PacketSignal translateAndDefault(BedrockPacket packet) { @@ -149,9 +158,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { responsePacket.setCompressionAlgorithm(algorithm); responsePacket.setCompressionThreshold(512); session.sendUpstreamPacketImmediately(responsePacket); + session.getUpstream().getSession().getPeer().setCompression(compressionStrategy); - session.getUpstream().getSession().setCompression(algorithm); - session.getUpstream().getSession().setCompressionLevel(this.geyser.getConfig().getBedrock().getCompressionLevel()); networkSettingsRequested = true; return PacketSignal.HANDLED; } 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 415e61ac2..8aa16fe48 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 @@ -41,6 +41,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; +import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -118,6 +119,8 @@ public final class BlockRegistryPopulator { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_20_40", Bedrock_v622.CODEC.getProtocolVersion()), Conversion630_622::remapBlock) .put(ObjectIntPair.of("1_20_50", Bedrock_v630.CODEC.getProtocolVersion()), tag -> tag) + // Only changes in 1.20.60 are hard_stained_glass (an EDU only block) + .put(ObjectIntPair.of("1_20_60", Bedrock_v649.CODEC.getProtocolVersion()), tag -> tag) .build(); // We can keep this strong as nothing should be garbage collected @@ -139,6 +142,7 @@ public final class BlockRegistryPopulator { builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states builder.remove("name_hash"); // Quick workaround - was added in 1.19.20 builder.remove("network_id"); // Added in 1.19.80 - ???? + builder.remove("block_id"); // Added in 1.20.60 //TODO verify this can be just removed //noinspection UnstableApiUsage builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states"))); vanillaBlockStates.set(i, builder.build()); @@ -154,6 +158,7 @@ public final class BlockRegistryPopulator { List customExtBlockStates = new ArrayList<>(); int[] remappedVanillaIds = new int[0]; if (BlockRegistries.CUSTOM_BLOCKS.get().length != 0) { + CustomBlockRegistryPopulator.BLOCK_ID.set(CustomBlockRegistryPopulator.START_OFFSET); for (CustomBlockData customBlock : BlockRegistries.CUSTOM_BLOCKS.get()) { customBlockProperties.add(CustomBlockRegistryPopulator.generateBlockPropertyData(customBlock, protocolVersion)); CustomBlockRegistryPopulator.generateCustomBlockStates(customBlock, customBlockStates, customExtBlockStates); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java new file mode 100644 index 000000000..ed66322ff --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.populator; + +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + + +public class Conversion630_649 { + + static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) { + if (mapping.getBedrockIdentifier().equalsIgnoreCase("minecraft:scute")) { + return mapping.withBedrockIdentifier("minecraft:turtle_scute"); + } + return mapping; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java index d27a2ed49..c536d739c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CreativeItemRegistryPopulator.java @@ -124,6 +124,7 @@ public class CreativeItemRegistryPopulator { builder.remove("name_hash"); builder.remove("network_id"); builder.remove("version"); + builder.remove("block_id"); blockDefinition = blockMappings.getDefinition(builder.build()); } catch (IOException e) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index 2a9948f45..ea33450bf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -28,12 +28,14 @@ import org.geysermc.geyser.level.block.GeyserCustomBlockData; import org.geysermc.geyser.level.block.GeyserCustomBlockState; import org.geysermc.geyser.level.block.GeyserGeometryComponent; import org.geysermc.geyser.level.block.GeyserMaterialInstance; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.util.MathUtils; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -41,6 +43,13 @@ import java.util.Map; import java.util.Set; public class CustomBlockRegistryPopulator { + + // Since 1.20.60, custom blocks need a block_id in their nbt tag + public static AtomicInteger BLOCK_ID = new AtomicInteger(); + + // Custom block id's start at 10000, and count up + public static final int START_OFFSET = 10000; + /** * The stage of population */ @@ -89,7 +98,7 @@ public class CustomBlockRegistryPopulator { GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { @Override public void register(@NonNull CustomBlockData customBlockData) { - if (customBlockData.name().length() == 0) { + if (customBlockData.name().isEmpty()) { throw new IllegalArgumentException("Custom block name must have at least 1 character."); } if (!CUSTOM_BLOCK_NAMES.add(customBlockData.name())) { @@ -179,17 +188,17 @@ public class CustomBlockRegistryPopulator { }); BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(blockStateOverrides); - if (blockStateOverrides.size() != 0) { + if (!blockStateOverrides.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + blockStateOverrides.size() + " custom block overrides."); } BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.set(CUSTOM_BLOCK_ITEM_OVERRIDES); - if (CUSTOM_BLOCK_ITEM_OVERRIDES.size() != 0) { + if (!CUSTOM_BLOCK_ITEM_OVERRIDES.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + CUSTOM_BLOCK_ITEM_OVERRIDES.size() + " custom block item overrides."); } BlockRegistries.EXTENDED_COLLISION_BOXES.set(extendedCollisionBoxes); - if (extendedCollisionBoxes.size() != 0) { + if (!extendedCollisionBoxes.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + extendedCollisionBoxes.size() + " custom block extended collision boxes."); } } @@ -199,7 +208,7 @@ public class CustomBlockRegistryPopulator { */ private static void populateNonVanilla() { BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.set(NON_VANILLA_BLOCK_STATE_OVERRIDES); - if (NON_VANILLA_BLOCK_STATE_OVERRIDES.size() != 0) { + if (!NON_VANILLA_BLOCK_STATE_OVERRIDES.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + NON_VANILLA_BLOCK_STATE_OVERRIDES.size() + " non-vanilla block overrides."); } } @@ -209,7 +218,7 @@ public class CustomBlockRegistryPopulator { */ private static void registration() { BlockRegistries.CUSTOM_BLOCKS.set(CUSTOM_BLOCKS.toArray(new CustomBlockData[0])); - if (CUSTOM_BLOCKS.size() != 0) { + if (!CUSTOM_BLOCKS.isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + CUSTOM_BLOCKS.size() + " custom blocks."); } } @@ -279,7 +288,7 @@ public class CustomBlockRegistryPopulator { CreativeCategory creativeCategory = customBlock.creativeCategory() != null ? customBlock.creativeCategory() : CreativeCategory.NONE; String creativeGroup = customBlock.creativeGroup() != null ? customBlock.creativeGroup() : ""; - NbtMap propertyTag = NbtMap.builder() + NbtMapBuilder propertyTag = NbtMap.builder() .putCompound("components", CustomBlockRegistryPopulator.convertComponents(customBlock.components(), protocolVersion)) // this is required or the client will crash // in the future, this can be used to replace items in the creative inventory @@ -292,9 +301,14 @@ public class CustomBlockRegistryPopulator { // meaning of this version is unknown, but it's required for tags to work and should probably be checked periodically .putInt("molangVersion", 1) .putList("permutations", NbtType.COMPOUND, permutations) - .putList("properties", NbtType.COMPOUND, properties) - .build(); - return new BlockPropertyData(customBlock.identifier(), propertyTag); + .putList("properties", NbtType.COMPOUND, properties); + + if (GameProtocol.is1_20_60orHigher(protocolVersion)) { + propertyTag.putCompound("vanilla_block_data", NbtMap.builder() + .putInt("block_id", BLOCK_ID.getAndIncrement()) + .build()); + } + return new BlockPropertyData(customBlock.identifier(), propertyTag.build()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java index 6be1aac4c..e1d67399f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java @@ -44,6 +44,7 @@ import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.components.WearableSlot; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.ItemMapping; @@ -97,10 +98,10 @@ public class CustomItemRegistryPopulator { } } - public static GeyserCustomMappingData registerCustomItem(String customItemName, Item javaItem, GeyserMappingItem mapping, CustomItemData customItemData, int bedrockId) { + public static GeyserCustomMappingData registerCustomItem(String customItemName, Item javaItem, GeyserMappingItem mapping, CustomItemData customItemData, int bedrockId, int protocolVersion) { ItemDefinition itemDefinition = new SimpleItemDefinition(customItemName, bedrockId, true); - NbtMapBuilder builder = createComponentNbt(customItemData, javaItem, mapping, customItemName, bedrockId); + NbtMapBuilder builder = createComponentNbt(customItemData, javaItem, mapping, customItemName, bedrockId, protocolVersion); ComponentItemData componentItemData = new ComponentItemData(customItemName, builder.build()); return new GeyserCustomMappingData(componentItemData, itemDefinition, customItemName, bedrockId); @@ -124,7 +125,7 @@ public class CustomItemRegistryPopulator { return true; } - public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItemData customItemData, int customItemId) { + public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItemData customItemData, int customItemId, int protocolVersion) { String customIdentifier = customItemData.identifier(); Set repairMaterials = customItemData.repairMaterials(); @@ -152,14 +153,14 @@ public class CustomItemRegistryPopulator { .build(); NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, - customItemData.creativeCategory(), customItemData.creativeGroup(), customItemData.isHat(), customItemData.displayHandheld()); + customItemData.creativeCategory(), customItemData.creativeGroup(), customItemData.isHat(), customItemData.displayHandheld(), protocolVersion); ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build()); return new NonVanillaItemRegistration(componentItemData, item, customItemMapping); } private static NbtMapBuilder createComponentNbt(CustomItemData customItemData, Item javaItem, GeyserMappingItem mapping, - String customItemName, int customItemId) { + String customItemName, int customItemId, int protocolVersion) { NbtMapBuilder builder = NbtMap.builder(); builder.putString("name", customItemName) .putInt("id", customItemId); @@ -167,7 +168,7 @@ public class CustomItemRegistryPopulator { NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder(); - setupBasicItemInfo(javaItem.maxDamage(), javaItem.maxStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder); + setupBasicItemInfo(javaItem.maxDamage(), javaItem.maxStackSize(), mapping.getToolType() != null || customItemData.displayHandheld(), customItemData, itemProperties, componentBuilder, protocolVersion); boolean canDestroyInCreative = true; if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here. @@ -210,7 +211,7 @@ public class CustomItemRegistryPopulator { @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName, int customItemId, OptionalInt creativeCategory, - String creativeGroup, boolean isHat, boolean displayHandheld) { + String creativeGroup, boolean isHat, boolean displayHandheld, int protocolVersion) { NbtMapBuilder builder = NbtMap.builder(); builder.putString("name", customItemName) .putInt("id", customItemId); @@ -218,7 +219,7 @@ public class CustomItemRegistryPopulator { NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder(); - setupBasicItemInfo(customItemData.maxDamage(), customItemData.stackSize(), displayHandheld, customItemData, itemProperties, componentBuilder); + setupBasicItemInfo(customItemData.maxDamage(), customItemData.stackSize(), displayHandheld, customItemData, itemProperties, componentBuilder, protocolVersion); boolean canDestroyInCreative = true; if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here. @@ -258,10 +259,21 @@ public class CustomItemRegistryPopulator { return builder; } - private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) { - itemProperties.putCompound("minecraft:icon", NbtMap.builder() - .putString("texture", customItemData.icon()) - .build()); + private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int protocolVersion) { + NbtMap iconMap; + if (GameProtocol.is1_20_60orHigher(protocolVersion)) { + iconMap = NbtMap.builder() + .putCompound("textures", NbtMap.builder() + .putString("default", customItemData.icon()) + .build()) + .build(); + } else { + iconMap = NbtMap.builder() + .putString("texture", customItemData.icon()) + .build(); + } + itemProperties.putCompound("minecraft:icon", iconMap); + componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", customItemData.displayName()).build()); // Add a Geyser tag to the item, allowing Molang queries diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomSkullRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomSkullRegistryPopulator.java index 02d9a75ec..ec7243396 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomSkullRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomSkullRegistryPopulator.java @@ -130,7 +130,7 @@ public class CustomSkullRegistryPopulator { } }); - if (BlockRegistries.CUSTOM_SKULLS.get().size() != 0) { + if (!BlockRegistries.CUSTOM_SKULLS.get().isEmpty()) { GeyserImpl.getInstance().getLogger().info("Registered " + BlockRegistries.CUSTOM_SKULLS.get().size() + " custom skulls as custom blocks."); } } 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 bc2cf4a43..539452169 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 @@ -40,6 +40,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; +import org.cloudburstmc.protocol.bedrock.codec.v649.Bedrock_v649; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -59,6 +60,7 @@ import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.item.GeyserCustomMappingData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.*; @@ -89,6 +91,7 @@ public class ItemRegistryPopulator { List paletteVersions = new ArrayList<>(3); paletteVersions.add(new PaletteVersion("1_20_40", Bedrock_v622.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion630_622::remapItem)); paletteVersions.add(new PaletteVersion("1_20_50", Bedrock_v630.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_20_60", Bedrock_v649.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion630_649::remapItem)); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -272,7 +275,7 @@ public class ItemRegistryPopulator { if (firstPass) { firstPass = false; - if (states.size() == 0) { + if (states.isEmpty()) { // No need to iterate and find all block states - this is the one, as there can't be any others bedrockBlock = bedrockBlockRuntimeId; break; @@ -288,7 +291,7 @@ public class ItemRegistryPopulator { requiredBlockStatesBuilder.remove(nbtEntry.getKey()); } } - if (requiredBlockStatesBuilder.size() == 0) { + if (requiredBlockStatesBuilder.isEmpty()) { // There are no required block states // E.G. there was only a direction property that is no longer in play // (States that are important include color for glass) @@ -420,7 +423,7 @@ public class ItemRegistryPopulator { } GeyserCustomMappingData customMapping = CustomItemRegistryPopulator.registerCustomItem( - customItemName, javaItem, mappingItem, customItem, customProtocolId + customItemName, javaItem, mappingItem, customItem, customProtocolId, palette.protocolVersion ); // ComponentItemData - used to register some custom properties componentItemData.add(customMapping.componentItemData()); @@ -495,7 +498,7 @@ public class ItemRegistryPopulator { .count(1) .build()); - registerFurnaceMinecart(nextFreeBedrockId++, componentItemData); + registerFurnaceMinecart(nextFreeBedrockId++, componentItemData, palette.protocolVersion); // Register any completely custom items given to us IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids @@ -508,7 +511,7 @@ public class ItemRegistryPopulator { } int customItemId = nextFreeBedrockId++; - NonVanillaItemRegistration registration = CustomItemRegistryPopulator.registerCustomItem(customItem, customItemId); + NonVanillaItemRegistration registration = CustomItemRegistryPopulator.registerCustomItem(customItem, customItemId, palette.protocolVersion); componentItemData.add(registration.componentItemData()); ItemMapping mapping = registration.mapping(); @@ -585,7 +588,7 @@ public class ItemRegistryPopulator { } } - private static void registerFurnaceMinecart(int nextFreeBedrockId, List componentItemData) { + private static void registerFurnaceMinecart(int nextFreeBedrockId, List componentItemData, int protocolVersion) { NbtMapBuilder builder = NbtMap.builder(); builder.putString("name", "geysermc:furnace_minecart") .putInt("id", nextFreeBedrockId); @@ -594,11 +597,20 @@ public class ItemRegistryPopulator { NbtMapBuilder componentBuilder = NbtMap.builder(); // Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already. - itemProperties.putCompound("minecraft:icon", NbtMap.builder() - .putString("texture", "minecart_furnace") - .putString("frame", "0.000000") - .putInt("frame_version", 1) - .putString("legacy_id", "").build()); + // Not so conveniently, the way to set an icon changed in 1.20.60 + NbtMap iconMap; + if (GameProtocol.is1_20_60orHigher(protocolVersion)) { + iconMap = NbtMap.builder() + .putCompound("textures", NbtMap.builder() + .putString("default", "minecart_furnace") + .build()) + .build(); + } else { + iconMap = NbtMap.builder() + .putString("texture", "minecart_furnace") + .build(); + } + itemProperties.putCompound("minecraft:icon", iconMap); componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build()); // Indicate that the arm animation should play on rails diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 19c587bf8..8a35bbb5c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -72,6 +72,7 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.geyser.util.DimensionUtils; import java.io.IOException; import java.util.BitSet; @@ -522,6 +523,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator