Support Bedrock 1.20.60 (#4415)

* Start on 1.20.60 support

* fix dimension switching

* Fix custom item icons... thanks mojang

* fix custom blocks/custom skulls breaking all block mappings

* - replace 10000 with static final variable

* fix: creative items not being found

* versioned custom item registration

* fix compression level setting
* show 1.20.61 as supported
This commit is contained in:
chris 2024-02-06 20:11:17 +01:00 committed by GitHub
parent 226a4bb151
commit 19a3dc3c4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 11929 additions and 41 deletions

View file

@ -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.
*

View file

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

View file

@ -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.<ObjectIntPair<String>, 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<CustomBlockState> 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);

View file

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

View file

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

View file

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

View file

@ -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<String> 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

View file

@ -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.");
}
}

View file

@ -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<PaletteVersion> 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> componentItemData) {
private static void registerFurnaceMinecart(int nextFreeBedrockId, List<ComponentItemData> 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

View file

@ -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<Clientbo
levelChunkPacket.setChunkX(packet.getX());
levelChunkPacket.setChunkZ(packet.getZ());
levelChunkPacket.setData(Unpooled.wrappedBuffer(payload));
levelChunkPacket.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
session.sendUpstreamPacket(levelChunkPacket);
if (!lecterns.isEmpty()) {

View file

@ -244,6 +244,7 @@ public class ChunkUtils {
byteBuf.readBytes(payload);
LevelChunkPacket data = new LevelChunkPacket();
data.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
data.setChunkX(chunkX);
data.setChunkZ(chunkZ);
data.setSubChunksLength(0);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,10 +9,10 @@ netty = "4.1.103.Final"
guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1"
protocol = "3.0.0.Beta1-20231206.150507-114"
protocol-connection = "3.0.0.Beta1-20231206.150507-113"
protocol = "3.0.0.Beta1-20240204.134050-120"
protocol-connection = "3.0.0.Beta1-20240204.134050-119"
raknet = "1.0.0.CR1-20231206.145325-12"
blockstateupdater="1.20.50-20231106.161340-1"
blockstateupdater="1.20.60-20240129.140535-1"
mcauthlib = "d9d773e"
mcprotocollib = "1.20.4-2-20240116.220521-7"
adventure = "4.14.0"