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.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622;
import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; 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.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.session.GeyserSession; 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 * Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports. * 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 * 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() SUPPORTED_BEDROCK_CODECS.add(Bedrock_v622.CODEC.toBuilder()
.minecraftVersion("1.20.40/1.20.41") .minecraftVersion("1.20.40/1.20.41")
.build()); .build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() SUPPORTED_BEDROCK_CODECS.add(Bedrock_v630.CODEC.toBuilder()
.minecraftVersion("1.20.50/1.20.51") .minecraftVersion("1.20.50/1.20.51")
.build()); .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(); 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. * 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.ExperimentData;
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; 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.BedrockPacket;
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket; import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket; 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.ResourcePacksInfoPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket;
import org.cloudburstmc.protocol.common.PacketSignal; import org.cloudburstmc.protocol.common.PacketSignal;
import org.cloudburstmc.protocol.common.util.Zlib;
import org.geysermc.geyser.Constants; import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.AuthType;
@ -77,11 +81,16 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
private boolean networkSettingsRequested = false; private boolean networkSettingsRequested = false;
private final Deque<String> packsToSent = new ArrayDeque<>(); private final Deque<String> packsToSent = new ArrayDeque<>();
private final CompressionStrategy compressionStrategy;
private SessionLoadResourcePacksEventImpl resourcePackLoadEvent; private SessionLoadResourcePacksEventImpl resourcePackLoadEvent;
public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) { public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) {
super(geyser, 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) { private PacketSignal translateAndDefault(BedrockPacket packet) {
@ -149,9 +158,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
responsePacket.setCompressionAlgorithm(algorithm); responsePacket.setCompressionAlgorithm(algorithm);
responsePacket.setCompressionThreshold(512); responsePacket.setCompressionThreshold(512);
session.sendUpstreamPacketImmediately(responsePacket); 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; networkSettingsRequested = true;
return PacketSignal.HANDLED; return PacketSignal.HANDLED;
} }

View File

@ -41,6 +41,7 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622;
import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; 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.BlockPropertyData;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
@ -118,6 +119,8 @@ public final class BlockRegistryPopulator {
var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder() 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_40", Bedrock_v622.CODEC.getProtocolVersion()), Conversion630_622::remapBlock)
.put(ObjectIntPair.of("1_20_50", Bedrock_v630.CODEC.getProtocolVersion()), tag -> tag) .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(); .build();
// We can keep this strong as nothing should be garbage collected // 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("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("name_hash"); // Quick workaround - was added in 1.19.20
builder.remove("network_id"); // Added in 1.19.80 - ???? 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 //noinspection UnstableApiUsage
builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states"))); builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states")));
vanillaBlockStates.set(i, builder.build()); vanillaBlockStates.set(i, builder.build());
@ -154,6 +158,7 @@ public final class BlockRegistryPopulator {
List<CustomBlockState> customExtBlockStates = new ArrayList<>(); List<CustomBlockState> customExtBlockStates = new ArrayList<>();
int[] remappedVanillaIds = new int[0]; int[] remappedVanillaIds = new int[0];
if (BlockRegistries.CUSTOM_BLOCKS.get().length != 0) { if (BlockRegistries.CUSTOM_BLOCKS.get().length != 0) {
CustomBlockRegistryPopulator.BLOCK_ID.set(CustomBlockRegistryPopulator.START_OFFSET);
for (CustomBlockData customBlock : BlockRegistries.CUSTOM_BLOCKS.get()) { for (CustomBlockData customBlock : BlockRegistries.CUSTOM_BLOCKS.get()) {
customBlockProperties.add(CustomBlockRegistryPopulator.generateBlockPropertyData(customBlock, protocolVersion)); customBlockProperties.add(CustomBlockRegistryPopulator.generateBlockPropertyData(customBlock, protocolVersion));
CustomBlockRegistryPopulator.generateCustomBlockStates(customBlock, customBlockStates, customExtBlockStates); 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("name_hash");
builder.remove("network_id"); builder.remove("network_id");
builder.remove("version"); builder.remove("version");
builder.remove("block_id");
blockDefinition = blockMappings.getDefinition(builder.build()); blockDefinition = blockMappings.getDefinition(builder.build());
} catch (IOException e) { } 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.GeyserCustomBlockState;
import org.geysermc.geyser.level.block.GeyserGeometryComponent; import org.geysermc.geyser.level.block.GeyserGeometryComponent;
import org.geysermc.geyser.level.block.GeyserMaterialInstance; import org.geysermc.geyser.level.block.GeyserMaterialInstance;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.mappings.MappingsConfigReader; import org.geysermc.geyser.registry.mappings.MappingsConfigReader;
import org.geysermc.geyser.registry.type.CustomSkull; import org.geysermc.geyser.registry.type.CustomSkull;
import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.MathUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -41,6 +43,13 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
public class CustomBlockRegistryPopulator { 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 * The stage of population
*/ */
@ -89,7 +98,7 @@ public class CustomBlockRegistryPopulator {
GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() {
@Override @Override
public void register(@NonNull CustomBlockData customBlockData) { 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."); throw new IllegalArgumentException("Custom block name must have at least 1 character.");
} }
if (!CUSTOM_BLOCK_NAMES.add(customBlockData.name())) { if (!CUSTOM_BLOCK_NAMES.add(customBlockData.name())) {
@ -179,17 +188,17 @@ public class CustomBlockRegistryPopulator {
}); });
BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(blockStateOverrides); BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(blockStateOverrides);
if (blockStateOverrides.size() != 0) { if (!blockStateOverrides.isEmpty()) {
GeyserImpl.getInstance().getLogger().info("Registered " + blockStateOverrides.size() + " custom block overrides."); GeyserImpl.getInstance().getLogger().info("Registered " + blockStateOverrides.size() + " custom block overrides.");
} }
BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.set(CUSTOM_BLOCK_ITEM_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."); GeyserImpl.getInstance().getLogger().info("Registered " + CUSTOM_BLOCK_ITEM_OVERRIDES.size() + " custom block item overrides.");
} }
BlockRegistries.EXTENDED_COLLISION_BOXES.set(extendedCollisionBoxes); 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."); GeyserImpl.getInstance().getLogger().info("Registered " + extendedCollisionBoxes.size() + " custom block extended collision boxes.");
} }
} }
@ -199,7 +208,7 @@ public class CustomBlockRegistryPopulator {
*/ */
private static void populateNonVanilla() { private static void populateNonVanilla() {
BlockRegistries.NON_VANILLA_BLOCK_STATE_OVERRIDES.set(NON_VANILLA_BLOCK_STATE_OVERRIDES); 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."); 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() { private static void registration() {
BlockRegistries.CUSTOM_BLOCKS.set(CUSTOM_BLOCKS.toArray(new CustomBlockData[0])); 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."); 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; CreativeCategory creativeCategory = customBlock.creativeCategory() != null ? customBlock.creativeCategory() : CreativeCategory.NONE;
String creativeGroup = customBlock.creativeGroup() != null ? customBlock.creativeGroup() : ""; String creativeGroup = customBlock.creativeGroup() != null ? customBlock.creativeGroup() : "";
NbtMap propertyTag = NbtMap.builder() NbtMapBuilder propertyTag = NbtMap.builder()
.putCompound("components", CustomBlockRegistryPopulator.convertComponents(customBlock.components(), protocolVersion)) .putCompound("components", CustomBlockRegistryPopulator.convertComponents(customBlock.components(), protocolVersion))
// this is required or the client will crash // this is required or the client will crash
// in the future, this can be used to replace items in the creative inventory // 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 // meaning of this version is unknown, but it's required for tags to work and should probably be checked periodically
.putInt("molangVersion", 1) .putInt("molangVersion", 1)
.putList("permutations", NbtType.COMPOUND, permutations) .putList("permutations", NbtType.COMPOUND, permutations)
.putList("properties", NbtType.COMPOUND, properties) .putList("properties", NbtType.COMPOUND, properties);
.build();
return new BlockPropertyData(customBlock.identifier(), propertyTag); 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.Items;
import org.geysermc.geyser.item.components.WearableSlot; import org.geysermc.geyser.item.components.WearableSlot;
import org.geysermc.geyser.item.type.Item; 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.mappings.MappingsConfigReader;
import org.geysermc.geyser.registry.type.GeyserMappingItem; import org.geysermc.geyser.registry.type.GeyserMappingItem;
import org.geysermc.geyser.registry.type.ItemMapping; 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); 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()); ComponentItemData componentItemData = new ComponentItemData(customItemName, builder.build());
return new GeyserCustomMappingData(componentItemData, itemDefinition, customItemName, bedrockId); return new GeyserCustomMappingData(componentItemData, itemDefinition, customItemName, bedrockId);
@ -124,7 +125,7 @@ public class CustomItemRegistryPopulator {
return true; return true;
} }
public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItemData customItemData, int customItemId) { public static NonVanillaItemRegistration registerCustomItem(NonVanillaCustomItemData customItemData, int customItemId, int protocolVersion) {
String customIdentifier = customItemData.identifier(); String customIdentifier = customItemData.identifier();
Set<String> repairMaterials = customItemData.repairMaterials(); Set<String> repairMaterials = customItemData.repairMaterials();
@ -152,14 +153,14 @@ public class CustomItemRegistryPopulator {
.build(); .build();
NbtMapBuilder builder = createComponentNbt(customItemData, customItemData.identifier(), customItemId, 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()); ComponentItemData componentItemData = new ComponentItemData(customIdentifier, builder.build());
return new NonVanillaItemRegistration(componentItemData, item, customItemMapping); return new NonVanillaItemRegistration(componentItemData, item, customItemMapping);
} }
private static NbtMapBuilder createComponentNbt(CustomItemData customItemData, Item javaItem, GeyserMappingItem mapping, private static NbtMapBuilder createComponentNbt(CustomItemData customItemData, Item javaItem, GeyserMappingItem mapping,
String customItemName, int customItemId) { String customItemName, int customItemId, int protocolVersion) {
NbtMapBuilder builder = NbtMap.builder(); NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", customItemName) builder.putString("name", customItemName)
.putInt("id", customItemId); .putInt("id", customItemId);
@ -167,7 +168,7 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = 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; boolean canDestroyInCreative = true;
if (mapping.getToolType() != null) { // This is not using the isTool boolean because it is not just a render type here. 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") @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName, private static NbtMapBuilder createComponentNbt(NonVanillaCustomItemData customItemData, String customItemName,
int customItemId, OptionalInt creativeCategory, int customItemId, OptionalInt creativeCategory,
String creativeGroup, boolean isHat, boolean displayHandheld) { String creativeGroup, boolean isHat, boolean displayHandheld, int protocolVersion) {
NbtMapBuilder builder = NbtMap.builder(); NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", customItemName) builder.putString("name", customItemName)
.putInt("id", customItemId); .putInt("id", customItemId);
@ -218,7 +219,7 @@ public class CustomItemRegistryPopulator {
NbtMapBuilder itemProperties = NbtMap.builder(); NbtMapBuilder itemProperties = NbtMap.builder();
NbtMapBuilder componentBuilder = 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; boolean canDestroyInCreative = true;
if (customItemData.toolType() != null) { // This is not using the isTool boolean because it is not just a render type here. 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; return builder;
} }
private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder) { private static void setupBasicItemInfo(int maxDamage, int stackSize, boolean displayHandheld, CustomItemData customItemData, NbtMapBuilder itemProperties, NbtMapBuilder componentBuilder, int protocolVersion) {
itemProperties.putCompound("minecraft:icon", NbtMap.builder() NbtMap iconMap;
.putString("texture", customItemData.icon()) if (GameProtocol.is1_20_60orHigher(protocolVersion)) {
.build()); 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()); componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", customItemData.displayName()).build());
// Add a Geyser tag to the item, allowing Molang queries // 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."); 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.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622; import org.cloudburstmc.protocol.bedrock.codec.v622.Bedrock_v622;
import org.cloudburstmc.protocol.bedrock.codec.v630.Bedrock_v630; 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.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; 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.GeyserCustomMappingData;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.*; import org.geysermc.geyser.registry.type.*;
@ -89,6 +91,7 @@ public class ItemRegistryPopulator {
List<PaletteVersion> paletteVersions = new ArrayList<>(3); 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_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_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(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();
@ -272,7 +275,7 @@ public class ItemRegistryPopulator {
if (firstPass) { if (firstPass) {
firstPass = false; 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 // No need to iterate and find all block states - this is the one, as there can't be any others
bedrockBlock = bedrockBlockRuntimeId; bedrockBlock = bedrockBlockRuntimeId;
break; break;
@ -288,7 +291,7 @@ public class ItemRegistryPopulator {
requiredBlockStatesBuilder.remove(nbtEntry.getKey()); requiredBlockStatesBuilder.remove(nbtEntry.getKey());
} }
} }
if (requiredBlockStatesBuilder.size() == 0) { if (requiredBlockStatesBuilder.isEmpty()) {
// There are no required block states // There are no required block states
// E.G. there was only a direction property that is no longer in play // E.G. there was only a direction property that is no longer in play
// (States that are important include color for glass) // (States that are important include color for glass)
@ -420,7 +423,7 @@ public class ItemRegistryPopulator {
} }
GeyserCustomMappingData customMapping = CustomItemRegistryPopulator.registerCustomItem( GeyserCustomMappingData customMapping = CustomItemRegistryPopulator.registerCustomItem(
customItemName, javaItem, mappingItem, customItem, customProtocolId customItemName, javaItem, mappingItem, customItem, customProtocolId, palette.protocolVersion
); );
// ComponentItemData - used to register some custom properties // ComponentItemData - used to register some custom properties
componentItemData.add(customMapping.componentItemData()); componentItemData.add(customMapping.componentItemData());
@ -495,7 +498,7 @@ public class ItemRegistryPopulator {
.count(1) .count(1)
.build()); .build());
registerFurnaceMinecart(nextFreeBedrockId++, componentItemData); registerFurnaceMinecart(nextFreeBedrockId++, componentItemData, palette.protocolVersion);
// Register any completely custom items given to us // Register any completely custom items given to us
IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids IntSet registeredJavaIds = new IntOpenHashSet(); // Used to check for duplicate item java ids
@ -508,7 +511,7 @@ public class ItemRegistryPopulator {
} }
int customItemId = nextFreeBedrockId++; int customItemId = nextFreeBedrockId++;
NonVanillaItemRegistration registration = CustomItemRegistryPopulator.registerCustomItem(customItem, customItemId); NonVanillaItemRegistration registration = CustomItemRegistryPopulator.registerCustomItem(customItem, customItemId, palette.protocolVersion);
componentItemData.add(registration.componentItemData()); componentItemData.add(registration.componentItemData());
ItemMapping mapping = registration.mapping(); 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(); NbtMapBuilder builder = NbtMap.builder();
builder.putString("name", "geysermc:furnace_minecart") builder.putString("name", "geysermc:furnace_minecart")
.putInt("id", nextFreeBedrockId); .putInt("id", nextFreeBedrockId);
@ -594,11 +597,20 @@ public class ItemRegistryPopulator {
NbtMapBuilder componentBuilder = NbtMap.builder(); NbtMapBuilder componentBuilder = NbtMap.builder();
// Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already. // Conveniently, as of 1.16.200, the furnace minecart has a texture AND translation string already.
itemProperties.putCompound("minecraft:icon", NbtMap.builder() // Not so conveniently, the way to set an icon changed in 1.20.60
.putString("texture", "minecart_furnace") NbtMap iconMap;
.putString("frame", "0.000000") if (GameProtocol.is1_20_60orHigher(protocolVersion)) {
.putInt("frame_version", 1) iconMap = NbtMap.builder()
.putString("legacy_id", "").build()); .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()); componentBuilder.putCompound("minecraft:display_name", NbtMap.builder().putString("value", "item.minecartFurnace.name").build());
// Indicate that the arm animation should play on rails // 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.translator.protocol.Translator;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockEntityUtils;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.geyser.util.DimensionUtils;
import java.io.IOException; import java.io.IOException;
import java.util.BitSet; import java.util.BitSet;
@ -522,6 +523,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
levelChunkPacket.setChunkX(packet.getX()); levelChunkPacket.setChunkX(packet.getX());
levelChunkPacket.setChunkZ(packet.getZ()); levelChunkPacket.setChunkZ(packet.getZ());
levelChunkPacket.setData(Unpooled.wrappedBuffer(payload)); levelChunkPacket.setData(Unpooled.wrappedBuffer(payload));
levelChunkPacket.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
session.sendUpstreamPacket(levelChunkPacket); session.sendUpstreamPacket(levelChunkPacket);
if (!lecterns.isEmpty()) { if (!lecterns.isEmpty()) {

View File

@ -244,6 +244,7 @@ public class ChunkUtils {
byteBuf.readBytes(payload); byteBuf.readBytes(payload);
LevelChunkPacket data = new LevelChunkPacket(); LevelChunkPacket data = new LevelChunkPacket();
data.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
data.setChunkX(chunkX); data.setChunkX(chunkX);
data.setChunkZ(chunkZ); data.setChunkZ(chunkZ);
data.setSubChunksLength(0); 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" guava = "29.0-jre"
gson = "2.3.1" # Provided by Spigot 1.8.8 gson = "2.3.1" # Provided by Spigot 1.8.8
websocket = "1.5.1" websocket = "1.5.1"
protocol = "3.0.0.Beta1-20231206.150507-114" protocol = "3.0.0.Beta1-20240204.134050-120"
protocol-connection = "3.0.0.Beta1-20231206.150507-113" protocol-connection = "3.0.0.Beta1-20240204.134050-119"
raknet = "1.0.0.CR1-20231206.145325-12" raknet = "1.0.0.CR1-20231206.145325-12"
blockstateupdater="1.20.50-20231106.161340-1" blockstateupdater="1.20.60-20240129.140535-1"
mcauthlib = "d9d773e" mcauthlib = "d9d773e"
mcprotocollib = "1.20.4-2-20240116.220521-7" mcprotocollib = "1.20.4-2-20240116.220521-7"
adventure = "4.14.0" adventure = "4.14.0"