1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Target 1.21.9 MCPL, write copper drop fallbacks/conversion, fix some stuff and write TODOs

This commit is contained in:
Eclipse
2025-09-23 15:29:58 +00:00
parent 22da1d614e
commit 0d4bc0f984
21 changed files with 186 additions and 48 deletions

View File

@@ -655,12 +655,12 @@ public final class EntityDefinitions {
.type(EntityType.PLAYER) .type(EntityType.PLAYER)
.height(1.8f).width(0.6f) .height(1.8f).width(0.6f)
.offset(1.62f) .offset(1.62f)
.addTranslator(null) // Player main hand
.addTranslator(MetadataTypes.BYTE, PlayerEntity::setSkinVisibility)
.addTranslator(MetadataTypes.FLOAT, PlayerEntity::setAbsorptionHearts) .addTranslator(MetadataTypes.FLOAT, PlayerEntity::setAbsorptionHearts)
.addTranslator(null) // Player score .addTranslator(null) // Player score
.addTranslator(MetadataTypes.BYTE, PlayerEntity::setSkinVisibility) .addTranslator(MetadataTypes.OPTIONAL_UNSIGNED_INT, PlayerEntity::setLeftParrot)
.addTranslator(null) // Player main hand .addTranslator(MetadataTypes.OPTIONAL_UNSIGNED_INT, PlayerEntity::setRightParrot)
.addTranslator(MetadataTypes.COMPOUND_TAG, PlayerEntity::setLeftParrot)
.addTranslator(MetadataTypes.COMPOUND_TAG, PlayerEntity::setRightParrot)
.build(); .build();
EntityDefinition<MobEntity> mobEntityBase = EntityDefinition.inherited(MobEntity::new, livingEntityBase) EntityDefinition<MobEntity> mobEntityBase = EntityDefinition.inherited(MobEntity::new, livingEntityBase)

View File

@@ -64,6 +64,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalInt;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -316,11 +317,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, ~entityMetadata.getPrimitiveValue() & 0xff); dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, ~entityMetadata.getPrimitiveValue() & 0xff);
} }
public void setLeftParrot(EntityMetadata<NbtMap, ?> entityMetadata) { public void setLeftParrot(EntityMetadata<OptionalInt, ?> entityMetadata) {
setParrot(entityMetadata.getValue(), true); setParrot(entityMetadata.getValue(), true);
} }
public void setRightParrot(EntityMetadata<NbtMap, ?> entityMetadata) { public void setRightParrot(EntityMetadata<OptionalInt, ?> entityMetadata) {
setParrot(entityMetadata.getValue(), false); setParrot(entityMetadata.getValue(), false);
} }
@@ -328,17 +329,17 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
* Sets the parrot occupying the shoulder. Bedrock Edition requires a full entity whereas Java Edition just * Sets the parrot occupying the shoulder. Bedrock Edition requires a full entity whereas Java Edition just
* spawns it from the NBT data provided * spawns it from the NBT data provided
*/ */
protected void setParrot(NbtMap tag, boolean isLeft) { protected void setParrot(OptionalInt variant, boolean isLeft) { // TODO test this as of 1.21.9
if (tag != null && !tag.isEmpty()) { if (variant.isPresent()) {
if ((isLeft && leftParrot != null) || (!isLeft && rightParrot != null)) { if ((isLeft && leftParrot != null) || (!isLeft && rightParrot != null)) {
// No need to update a parrot's data when it already exists // No need to update a parrot's data when it already exists
return; return;
} }
// The parrot is a separate entity in Bedrock, but part of the player entity in Java //TODO is a UUID provided in NBT? // The parrot is a separate entity in Bedrock, but part of the player entity in Java
ParrotEntity parrot = new ParrotEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), ParrotEntity parrot = new ParrotEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(),
null, EntityDefinitions.PARROT, position, motion, getYaw(), getPitch(), getHeadYaw()); null, EntityDefinitions.PARROT, position, motion, getYaw(), getPitch(), getHeadYaw());
parrot.spawnEntity(); parrot.spawnEntity();
parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, (Integer) tag.get("Variant")); parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, variant.getAsInt());
// Different position whether the parrot is left or right // Different position whether the parrot is left or right
float offset = isLeft ? 0.4f : -0.4f; float offset = isLeft ? 0.4f : -0.4f;
parrot.getDirtyMetadata().put(EntityDataTypes.SEAT_OFFSET, Vector3f.from(offset, -0.22, -0.1)); parrot.getDirtyMetadata().put(EntityDataTypes.SEAT_OFFSET, Vector3f.from(offset, -0.22, -0.1));

View File

@@ -213,9 +213,9 @@ public class DataComponentHashers {
register(DataComponentTypes.TRIM, RegistryHasher.ARMOR_TRIM); register(DataComponentTypes.TRIM, RegistryHasher.ARMOR_TRIM);
register(DataComponentTypes.DEBUG_STICK_STATE, MinecraftHasher.NBT_MAP); register(DataComponentTypes.DEBUG_STICK_STATE, MinecraftHasher.NBT_MAP);
register(DataComponentTypes.ENTITY_DATA, MinecraftHasher.NBT_MAP); // register(DataComponentTypes.ENTITY_DATA, MinecraftHasher.NBT_MAP); TODO 1.21.9
register(DataComponentTypes.BUCKET_ENTITY_DATA, MinecraftHasher.NBT_MAP); register(DataComponentTypes.BUCKET_ENTITY_DATA, MinecraftHasher.NBT_MAP);
register(DataComponentTypes.BLOCK_ENTITY_DATA, MinecraftHasher.NBT_MAP); // register(DataComponentTypes.BLOCK_ENTITY_DATA, MinecraftHasher.NBT_MAP); TODO 1.21.9
register(DataComponentTypes.INSTRUMENT, RegistryHasher.INSTRUMENT_COMPONENT); register(DataComponentTypes.INSTRUMENT, RegistryHasher.INSTRUMENT_COMPONENT);
register(DataComponentTypes.PROVIDES_TRIM_MATERIAL, RegistryHasher.PROVIDES_TRIM_MATERIAL); register(DataComponentTypes.PROVIDES_TRIM_MATERIAL, RegistryHasher.PROVIDES_TRIM_MATERIAL);
@@ -235,7 +235,7 @@ public class DataComponentHashers {
.optional("flight_duration", MinecraftHasher.BYTE, fireworks -> (byte) fireworks.getFlightDuration(), (byte) 0) .optional("flight_duration", MinecraftHasher.BYTE, fireworks -> (byte) fireworks.getFlightDuration(), (byte) 0)
.optionalList("explosions", RegistryHasher.FIREWORK_EXPLOSION, Fireworks::getExplosions)); .optionalList("explosions", RegistryHasher.FIREWORK_EXPLOSION, Fireworks::getExplosions));
register(DataComponentTypes.PROFILE, MinecraftHasher.GAME_PROFILE); // register(DataComponentTypes.PROFILE, MinecraftHasher.GAME_PROFILE); TODO 1.21.9
register(DataComponentTypes.NOTE_BLOCK_SOUND, MinecraftHasher.KEY); register(DataComponentTypes.NOTE_BLOCK_SOUND, MinecraftHasher.KEY);
register(DataComponentTypes.BANNER_PATTERNS, RegistryHasher.BANNER_PATTERN_LAYER.list()); register(DataComponentTypes.BANNER_PATTERNS, RegistryHasher.BANNER_PATTERN_LAYER.list());
register(DataComponentTypes.BASE_COLOR, MinecraftHasher.DYE_COLOR); register(DataComponentTypes.BASE_COLOR, MinecraftHasher.DYE_COLOR);

View File

@@ -49,7 +49,7 @@ public class PlayerHeadItem extends BlockItem {
// Use the correct color, determined by the rarity of the item // Use the correct color, determined by the rarity of the item
char rarity = Rarity.fromId(components.getOrDefault(DataComponentTypes.RARITY, Rarity.COMMON.ordinal())).getColor(); char rarity = Rarity.fromId(components.getOrDefault(DataComponentTypes.RARITY, Rarity.COMMON.ordinal())).getColor();
GameProfile profile = components.get(DataComponentTypes.PROFILE); /*GameProfile profile = components.get(DataComponentTypes.PROFILE);
if (profile != null) { if (profile != null) {
String name = profile.getName(); String name = profile.getName();
if (name != null) { if (name != null) {
@@ -62,6 +62,6 @@ public class PlayerHeadItem extends BlockItem {
builder.setCustomName(ChatColor.RESET + ChatColor.ESCAPE + rarity + builder.setCustomName(ChatColor.RESET + ChatColor.ESCAPE + rarity +
MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale())); MinecraftLocale.getLocaleString("block.minecraft.player_head", session.locale()));
} }
} }*/ // TODO 1.21.9
} }
} }

View File

@@ -36,6 +36,8 @@ import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.TypedEntityData;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
import java.util.Collections; import java.util.Collections;
import java.util.UUID; import java.util.UUID;
@@ -74,12 +76,11 @@ public class SkullBlock extends Block {
GeyserItemStack itemStack = GeyserItemStack.of(pickItem(state).getId(), 1); GeyserItemStack itemStack = GeyserItemStack.of(pickItem(state).getId(), 1);
// This is a universal block entity behavior, but hardcode how it works for now. // This is a universal block entity behavior, but hardcode how it works for now.
NbtMapBuilder builder = NbtMap.builder() NbtMapBuilder builder = NbtMap.builder()
.putString("id", "minecraft:skull")
.putInt("x", position.getX()) .putInt("x", position.getX())
.putInt("y", position.getY()) .putInt("y", position.getY())
.putInt("z", position.getZ()); .putInt("z", position.getZ());
DataComponents components = itemStack.getOrCreateComponents(); DataComponents components = itemStack.getOrCreateComponents();
components.put(DataComponentTypes.BLOCK_ENTITY_DATA, builder.build()); components.put(DataComponentTypes.BLOCK_ENTITY_DATA, new TypedEntityData<>(BlockEntityType.SKULL, builder.build()));
UUID uuid = skull.getUuid(); UUID uuid = skull.getUuid();
String texturesProperty = skull.getTexturesProperty(); String texturesProperty = skull.getTexturesProperty();
@@ -87,7 +88,7 @@ public class SkullBlock extends Block {
if (texturesProperty != null) { if (texturesProperty != null) {
profile.setProperties(Collections.singletonList(new GameProfile.Property("textures", texturesProperty))); profile.setProperties(Collections.singletonList(new GameProfile.Property("textures", texturesProperty)));
} }
components.put(DataComponentTypes.PROFILE, profile); // components.put(DataComponentTypes.PROFILE, profile); TODO 1.21.9
return itemStack.getItemStack(); return itemStack.getItemStack();
} }

View File

@@ -36,6 +36,7 @@ import org.cloudburstmc.protocol.bedrock.codec.v843.Bedrock_v843;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.geysermc.geyser.api.util.MinecraftVersion; import org.geysermc.geyser.api.util.MinecraftVersion;
import org.geysermc.geyser.impl.MinecraftVersionImpl; import org.geysermc.geyser.impl.MinecraftVersionImpl;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
import org.geysermc.mcprotocollib.protocol.codec.PacketCodec; import org.geysermc.mcprotocollib.protocol.codec.PacketCodec;
@@ -137,7 +138,9 @@ public final class GameProtocol {
/* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */
// There doesn't seem to be anything here at the moment... public static boolean is1_21_100(GeyserSession session) {
return session.protocolVersion() == Bedrock_v827.CODEC.getProtocolVersion();
}
/** /**
* Gets the supported Minecraft: Java Edition version names. * Gets the supported Minecraft: Java Edition version names.

View File

@@ -30,6 +30,7 @@ import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat; import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat;
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.CompressionStrategy;
@@ -288,7 +289,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
stackPacket.setGameVersion(session.getClientData().getGameVersion()); stackPacket.setGameVersion(session.getClientData().getGameVersion());
stackPacket.getResourcePacks().addAll(this.resourcePackLoadEvent.orderedPacks()); stackPacket.getResourcePacks().addAll(this.resourcePackLoadEvent.orderedPacks());
// TODO support copper drop on .100 if (GameProtocol.is1_21_100(session)) {
// Support copper age drop features (or some of them) in 1.21.100
stackPacket.getExperiments().add(new ExperimentData("y_2025_drop_3", true));
}
session.sendUpstreamPacket(stackPacket); session.sendUpstreamPacket(stackPacket);
} }

View File

@@ -59,6 +59,7 @@ import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.FlowerPotBlock; import org.geysermc.geyser.level.block.type.FlowerPotBlock;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.populator.conversion.Conversion827_819;
import org.geysermc.geyser.registry.populator.conversion.Conversion843_827; import org.geysermc.geyser.registry.populator.conversion.Conversion843_827;
import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.GeyserBedrockBlock; import org.geysermc.geyser.registry.type.GeyserBedrockBlock;
@@ -119,10 +120,10 @@ public final class BlockRegistryPopulator {
private static void registerBedrockBlocks() { private static void registerBedrockBlocks() {
var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder() var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder()
.put(ObjectIntPair.of("1_21_90", Bedrock_v818.CODEC.getProtocolVersion()), Conversion843_827::remapBlock) .put(ObjectIntPair.of("1_21_90", Bedrock_v818.CODEC.getProtocolVersion()), Conversion827_819::remapBlock)
.put(ObjectIntPair.of("1_21_90", Bedrock_v819.CODEC.getProtocolVersion()), Conversion843_827::remapBlock) .put(ObjectIntPair.of("1_21_90", Bedrock_v819.CODEC.getProtocolVersion()), Conversion827_819::remapBlock)
.put(ObjectIntPair.of("1_21_100", Bedrock_v827.CODEC.getProtocolVersion()), Conversion843_827::remapBlock) .put(ObjectIntPair.of("1_21_100", Bedrock_v827.CODEC.getProtocolVersion()), Conversion843_827::remapBlock)
.put(ObjectIntPair.of("1_21_110", Bedrock_v843.CODEC.getProtocolVersion()), tag -> tag) // TODO conversion? .put(ObjectIntPair.of("1_21_110", Bedrock_v843.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

View File

@@ -86,6 +86,7 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -119,11 +120,82 @@ public class ItemRegistryPopulator {
} }
public static void populate() { public static void populate() {
List<PaletteVersion> paletteVersions = new ArrayList<>(6); Map<Item, Item> eightTwoSevenFallbacks = new HashMap<>();
paletteVersions.add(new PaletteVersion("1_21_90", Bedrock_v818.CODEC.getProtocolVersion(), Map.of(Items.MUSIC_DISC_LAVA_CHICKEN, Items.MUSIC_DISC_CHIRP), Conversion843_827::remapItem)); eightTwoSevenFallbacks.put(Items.ACACIA_SHELF, Items.CHISELED_BOOKSHELF);
paletteVersions.add(new PaletteVersion("1_21_93", Bedrock_v819.CODEC.getProtocolVersion(), Conversion843_827::remapItem)); eightTwoSevenFallbacks.put(Items.BAMBOO_SHELF, Items.CHISELED_BOOKSHELF);
paletteVersions.add(new PaletteVersion("1_21_100", Bedrock_v827.CODEC.getProtocolVersion(), Conversion843_827::remapItem)); eightTwoSevenFallbacks.put(Items.BIRCH_SHELF, Items.CHISELED_BOOKSHELF);
paletteVersions.add(new PaletteVersion("1_21_110", Bedrock_v843.CODEC.getProtocolVersion())); // TODO fallback eightTwoSevenFallbacks.put(Items.CHERRY_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.CRIMSON_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.DARK_OAK_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.JUNGLE_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.MANGROVE_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.OAK_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.PALE_OAK_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.SPRUCE_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.WARPED_SHELF, Items.CHISELED_BOOKSHELF);
eightTwoSevenFallbacks.put(Items.COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.EXPOSED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.WEATHERED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.OXIDIZED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.WAXED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.WAXED_EXPOSED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.WAXED_WEATHERED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.WAXED_OXIDIZED_COPPER_BARS, Items.IRON_BARS);
eightTwoSevenFallbacks.put(Items.COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.EXPOSED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.WEATHERED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.OXIDIZED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.WAXED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.WAXED_EXPOSED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.WAXED_WEATHERED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.WAXED_OXIDIZED_COPPER_GOLEM_STATUE, Items.ARMOR_STAND);
eightTwoSevenFallbacks.put(Items.COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.EXPOSED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.WEATHERED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.OXIDIZED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.WAXED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.WAXED_EXPOSED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.WAXED_WEATHERED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.WAXED_OXIDIZED_COPPER_LANTERN, Items.LANTERN);
eightTwoSevenFallbacks.put(Items.EXPOSED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.WEATHERED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.OXIDIZED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.WAXED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.WAXED_EXPOSED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.WAXED_WEATHERED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.WAXED_OXIDIZED_LIGHTNING_ROD, Items.LIGHTNING_ROD);
eightTwoSevenFallbacks.put(Items.COPPER_TORCH, Items.TORCH);
eightTwoSevenFallbacks.put(Items.COPPER_HORSE_ARMOR, Items.LEATHER_HORSE_ARMOR);
Map<Item, Item> eightOneNineFallbacks = new HashMap<>(eightTwoSevenFallbacks);
eightOneNineFallbacks.put(Items.COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.EXPOSED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.WEATHERED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.OXIDIZED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.WAXED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.WAXED_EXPOSED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.WAXED_WEATHERED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.WAXED_OXIDIZED_COPPER_CHEST, Items.CHEST);
eightOneNineFallbacks.put(Items.COPPER_HELMET, Items.LEATHER_HELMET);
eightOneNineFallbacks.put(Items.COPPER_CHESTPLATE, Items.LEATHER_CHESTPLATE);
eightOneNineFallbacks.put(Items.COPPER_LEGGINGS, Items.LEATHER_LEGGINGS);
eightOneNineFallbacks.put(Items.COPPER_BOOTS, Items.LEATHER_BOOTS);
eightOneNineFallbacks.put(Items.COPPER_NUGGET, Items.IRON_NUGGET);
eightOneNineFallbacks.put(Items.COPPER_SWORD, Items.STONE_SWORD);
eightOneNineFallbacks.put(Items.COPPER_PICKAXE, Items.STONE_PICKAXE);
eightOneNineFallbacks.put(Items.COPPER_SHOVEL, Items.STONE_SHOVEL);
eightOneNineFallbacks.put(Items.COPPER_AXE, Items.STONE_AXE);
eightOneNineFallbacks.put(Items.COPPER_HOE, Items.STONE_HOE);
eightOneNineFallbacks.put(Items.COPPER_GOLEM_SPAWN_EGG, Items.IRON_GOLEM_SPAWN_EGG);
Map<Item, Item> eightOneEightFallbacks = new HashMap<>(eightOneNineFallbacks);
eightOneEightFallbacks.put(Items.MUSIC_DISC_LAVA_CHICKEN, Items.MUSIC_DISC_CHIRP);
List<PaletteVersion> paletteVersions = new ArrayList<>(4);
paletteVersions.add(new PaletteVersion("1_21_90", Bedrock_v818.CODEC.getProtocolVersion(), eightOneEightFallbacks, Conversion843_827::remapItem));
paletteVersions.add(new PaletteVersion("1_21_93", Bedrock_v819.CODEC.getProtocolVersion(), eightOneNineFallbacks, Conversion843_827::remapItem));
paletteVersions.add(new PaletteVersion("1_21_100", Bedrock_v827.CODEC.getProtocolVersion(), eightTwoSevenFallbacks, Conversion843_827::remapItem));
paletteVersions.add(new PaletteVersion("1_21_110", Bedrock_v843.CODEC.getProtocolVersion()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2025 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.conversion;
import org.cloudburstmc.nbt.NbtMap;
public class Conversion827_819 {
public static NbtMap remapBlock(NbtMap nbtMap) {
nbtMap = Conversion843_827.remapBlock(nbtMap);
final String name = nbtMap.getString("name");
if (name.endsWith("copper_chest")) {
return ConversionHelper.withName(nbtMap, "chest");
}
return nbtMap;
}
}

View File

@@ -35,21 +35,30 @@ public class Conversion843_827 {
public static NbtMap remapBlock(NbtMap nbtMap) { public static NbtMap remapBlock(NbtMap nbtMap) {
final String name = nbtMap.getString("name"); final String name = nbtMap.getString("name");
if (name.equals("minecraft:iron_chain")) { if (name.equals("minecraft:iron_chain") || name.endsWith("copper_chain")) {
return ConversionHelper.withName(nbtMap, "chain"); return ConversionHelper.withName(nbtMap, "chain");
} else if (name.equals("minecraft:lightning_rod")) { } else if (name.endsWith("lightning_rod")) {
NbtMapBuilder statesWithoutPoweredBit = nbtMap.getCompound("states").toBuilder(); NbtMapBuilder statesWithoutPoweredBit = nbtMap.getCompound("states").toBuilder();
statesWithoutPoweredBit.remove("powered_bit"); statesWithoutPoweredBit.remove("powered_bit");
return nbtMap.toBuilder() return nbtMap.toBuilder()
.putString("name", "minecraft:lightning_rod")
.putCompound("states", statesWithoutPoweredBit.build()) .putCompound("states", statesWithoutPoweredBit.build())
.build(); .build();
} else if (name.endsWith("_shelf") || name.endsWith("copper_golem_statue")) {
return ConversionHelper.withoutStates("unknown");
} else if (name.equals("minecraft:copper_torch")) {
return ConversionHelper.withName(nbtMap, "torch");
} else if (name.endsWith("copper_bars")) {
return ConversionHelper.withName(nbtMap, "iron_bars");
} else if (name.endsWith("copper_lantern")) {
return ConversionHelper.withName(nbtMap, "lantern");
} }
return nbtMap; return nbtMap;
} }
public static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { public static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
if (item == Items.IRON_CHAIN) { if (item == Items.IRON_CHAIN || item.javaIdentifier().endsWith("copper_chain")) {
return mapping.withBedrockIdentifier("minecraft:chain"); return mapping.withBedrockIdentifier("minecraft:chain");
} }
return mapping; return mapping;

View File

@@ -155,6 +155,7 @@ import org.geysermc.geyser.item.type.BlockItem;
import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.BedrockDimension;
import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.level.physics.CollisionManager;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.network.netty.LocalSession;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.BlockMappings; import org.geysermc.geyser.registry.type.BlockMappings;
@@ -1794,7 +1795,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true)); startGamePacket.getExperiments().add(new ExperimentData("upcoming_creator_features", true));
// Needed for certain molang queries used in blocks and items // Needed for certain molang queries used in blocks and items
startGamePacket.getExperiments().add(new ExperimentData("experimental_molang_features", true)); startGamePacket.getExperiments().add(new ExperimentData("experimental_molang_features", true));
// TODO Enable 2025 Content Drop 3 features on .100
// Enable 2025 Content Drop 3 features on 1.21.100
if (GameProtocol.is1_21_100(this)) {
startGamePacket.getExperiments().add(new ExperimentData("y_2025_drop_3", true));
}
startGamePacket.setVanillaVersion("*"); startGamePacket.setVanillaVersion("*");
startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setInventoriesServerAuthoritative(true);

View File

@@ -47,6 +47,7 @@ import org.geysermc.geyser.skin.SkinManager;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
// TODO 1.21.9
public class SkullCache { public class SkullCache {
private final int maxVisibleSkulls; private final int maxVisibleSkulls;
private final boolean cullingEnabled; private final boolean cullingEnabled;

View File

@@ -331,7 +331,7 @@ public abstract class InventoryTranslator<Type extends Inventory> {
GeyserItemStack javaItem = inventory.getItem(sourceSlot); GeyserItemStack javaItem = inventory.getItem(sourceSlot);
if (javaItem.asItem() == Items.PLAYER_HEAD if (javaItem.asItem() == Items.PLAYER_HEAD
&& javaItem.hasNonBaseComponents()) { && javaItem.hasNonBaseComponents()) {
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); //FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); TODO 1.21.9
} }
} else if (sourceSlot == 5) { } else if (sourceSlot == 5) {
// we are probably removing the head, so restore the original skin // we are probably removing the head, so restore the original skin

View File

@@ -111,7 +111,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator<PlayerInvento
if (i == 5 && if (i == 5 &&
item.asItem() == Items.PLAYER_HEAD && item.asItem() == Items.PLAYER_HEAD &&
item.hasNonBaseComponents()) { item.hasNonBaseComponents()) {
FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentTypes.PROFILE)); // FakeHeadProvider.setHead(session, session.getPlayerEntity(), item.getComponent(DataComponentTypes.PROFILE)); TODO 1.21.9
} }
} }
armorContentPacket.setContents(Arrays.asList(contents)); armorContentPacket.setContents(Arrays.asList(contents));
@@ -153,12 +153,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator<PlayerInvento
if (slot == 5) { if (slot == 5) {
// Check for custom skull // Check for custom skull
if (javaItem.asItem() == Items.PLAYER_HEAD /*if (javaItem.asItem() == Items.PLAYER_HEAD
&& javaItem.hasNonBaseComponents()) { && javaItem.hasNonBaseComponents()) {
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE));
} else { } else {
FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity()); FakeHeadProvider.restoreOriginalSkin(session, session.getPlayerEntity());
} }*/ // TODO
} }
if (slot >= 1 && slot <= 44) { if (slot >= 1 && slot <= 44) {
@@ -287,7 +287,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator<PlayerInvento
GeyserItemStack javaItem = inventory.getItem(sourceSlot); GeyserItemStack javaItem = inventory.getItem(sourceSlot);
if (javaItem.asItem() == Items.PLAYER_HEAD if (javaItem.asItem() == Items.PLAYER_HEAD
&& javaItem.hasNonBaseComponents()) { && javaItem.hasNonBaseComponents()) {
FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); // FakeHeadProvider.setHead(session, session.getPlayerEntity(), javaItem.getComponent(DataComponentTypes.PROFILE)); TODO
} }
} else if (sourceSlot == 5) { } else if (sourceSlot == 5) {
// we are probably removing the head, so restore the original skin // we are probably removing the head, so restore the original skin

View File

@@ -237,7 +237,7 @@ public final class ItemTranslator {
} }
if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) { if (bedrockItem.getJavaItem().equals(Items.PLAYER_HEAD)) {
translatePlayerHead(session, components.get(DataComponentTypes.PROFILE), builder); // translatePlayerHead(session, components.get(DataComponentTypes.PROFILE), builder); TODO 1.21.9
} }
translateCustomItem(components, builder, bedrockItem); translateCustomItem(components, builder, bedrockItem);
@@ -531,10 +531,10 @@ public final class ItemTranslator {
} }
if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) { if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) {
CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentTypes.PROFILE)); /*CustomSkull customSkull = getCustomSkull(itemStack.getComponent(DataComponentTypes.PROFILE));
if (customSkull != null) { if (customSkull != null) {
itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData()); itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData());
} }*/ // TODO
} }
ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack.getComponents(), mapping); ItemDefinition definition = CustomItemTranslator.getCustomItem(itemStack.getComponents(), mapping);

View File

@@ -62,7 +62,7 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
} }
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); Vector3f motion = packet.getMovement().toFloat();
float yaw = packet.getYaw(); float yaw = packet.getYaw();
float pitch = packet.getPitch(); float pitch = packet.getPitch();
float headYaw = packet.getHeadYaw(); float headYaw = packet.getHeadYaw();

View File

@@ -26,7 +26,6 @@
package org.geysermc.geyser.translator.protocol.java.entity; package org.geysermc.geyser.translator.protocol.java.entity;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityMotionPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.ItemEntity; import org.geysermc.geyser.entity.type.ItemEntity;
@@ -43,7 +42,7 @@ public class JavaSetEntityMotionTranslator extends PacketTranslator<ClientboundS
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
if (entity == null) return; if (entity == null) return;
entity.setMotion(Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ())); entity.setMotion(packet.getMovement().toFloat());
if (entity == session.getPlayerEntity().getVehicle() && entity instanceof AbstractHorseEntity) { if (entity == session.getPlayerEntity().getVehicle() && entity instanceof AbstractHorseEntity) {
// Horses for some reason teleport back when a SetEntityMotionPacket is sent while // Horses for some reason teleport back when a SetEntityMotionPacket is sent while

View File

@@ -61,12 +61,12 @@ public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetE
GeyserItemStack stack = GeyserItemStack.from(equipment.getItem()); GeyserItemStack stack = GeyserItemStack.from(equipment.getItem());
switch (equipment.getSlot()) { switch (equipment.getSlot()) {
case HELMET -> { case HELMET -> {
GameProfile profile = stack.getComponent(DataComponentTypes.PROFILE); /*GameProfile profile = stack.getComponent(DataComponentTypes.PROFILE);
if (livingEntity instanceof PlayerEntity && stack.asItem() == Items.PLAYER_HEAD && profile != null) { if (livingEntity instanceof PlayerEntity && stack.asItem() == Items.PLAYER_HEAD && profile != null) {
FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, profile); FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, profile);
} else { } else {
FakeHeadProvider.restoreOriginalSkin(session, livingEntity); FakeHeadProvider.restoreOriginalSkin(session, livingEntity);
} }*/ // TODO 1.21.9
livingEntity.setHelmet(stack); livingEntity.setHelmet(stack);
armorUpdated = true; armorUpdated = true;

View File

@@ -14,7 +14,7 @@ protocol-common = "3.0.0.Beta8-NO-ADVENTURE-SNAPSHOT"
protocol-codec = "3.0.0.Beta8-NO-ADVENTURE-SNAPSHOT" protocol-codec = "3.0.0.Beta8-NO-ADVENTURE-SNAPSHOT"
raknet = "1.0.0.CR3-20250811.214335-20" raknet = "1.0.0.CR3-20250811.214335-20"
minecraftauth = "4.1.1" minecraftauth = "4.1.1"
mcprotocollib = "1.21.7-20250915.111046-6" mcprotocollib = "1.21.9-SNAPSHOT"
adventure = "4.24.0" adventure = "4.24.0"
adventure-platform = "4.3.0" adventure-platform = "4.3.0"
junit = "5.9.2" junit = "5.9.2"

View File

@@ -20,7 +20,7 @@ include(":ap")
include(":api") include(":api")
include(":bungeecord") include(":bungeecord")
include(":fabric") include(":fabric")
include(":neoforge") //include(":neoforge") TODO 1.21.9
include(":mod") include(":mod")
include(":spigot") include(":spigot")
include(":standalone") include(":standalone")
@@ -32,7 +32,7 @@ include(":core")
// Specify project dirs // Specify project dirs
project(":bungeecord").projectDir = file("bootstrap/bungeecord") project(":bungeecord").projectDir = file("bootstrap/bungeecord")
project(":fabric").projectDir = file("bootstrap/mod/fabric") project(":fabric").projectDir = file("bootstrap/mod/fabric")
project(":neoforge").projectDir = file("bootstrap/mod/neoforge") //project(":neoforge").projectDir = file("bootstrap/mod/neoforge") TODO 1.21.9
project(":mod").projectDir = file("bootstrap/mod") project(":mod").projectDir = file("bootstrap/mod")
project(":spigot").projectDir = file("bootstrap/spigot") project(":spigot").projectDir = file("bootstrap/spigot")
project(":standalone").projectDir = file("bootstrap/standalone") project(":standalone").projectDir = file("bootstrap/standalone")