From 888756fa0449d52feaf3ed8b44a685d27979ccbf Mon Sep 17 00:00:00 2001 From: Jannis Guhl <128991638+guhlutions@users.noreply.github.com> Date: Fri, 13 Nov 2026 22:49:58 +0100 Subject: [PATCH 1/2] Handle Bedrock HUD slots, dropped item owners and snowlogging --- .../model/container/player/HudContainer.java | 14 +++++- .../rewriter/EntityMetadataRewriter.java | 3 ++ .../protocol/storage/ChunkTracker.java | 47 ++++++++++--------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/raphimc/viabedrock/api/model/container/player/HudContainer.java b/src/main/java/net/raphimc/viabedrock/api/model/container/player/HudContainer.java index 5ec975db5..9006e2489 100644 --- a/src/main/java/net/raphimc/viabedrock/api/model/container/player/HudContainer.java +++ b/src/main/java/net/raphimc/viabedrock/api/model/container/player/HudContainer.java @@ -24,8 +24,20 @@ public class HudContainer extends InventoryRedirectContainer { + private static final int LEGACY_SIZE = 54; + public HudContainer(final UserConnection user) { - super(user, (byte) ContainerID.CONTAINER_ID_PLAYER_ONLY_UI.getValue(), ContainerType.HUD, 54); + super(user, (byte) ContainerID.CONTAINER_ID_PLAYER_ONLY_UI.getValue(), ContainerType.HUD, 57); + } + + @Override + public boolean setItems(final BedrockItem[] items) { + if (items.length == LEGACY_SIZE) { + final BedrockItem[] expanded = BedrockItem.emptyArray(this.size()); + System.arraycopy(items, 0, expanded, 0, items.length); + return super.setItems(expanded); + } + return super.setItems(items); } @Override diff --git a/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java b/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java index 1f7d7982c..0eaef7d3a 100644 --- a/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java +++ b/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java @@ -369,6 +369,9 @@ public static boolean rewrite(final UserConnection user, final Entity entity, fi } } case OWNER -> { + if (entity.javaType().is(EntityTypes26_3.ITEM)) { + break; // The Bedrock server enforces who can pick up a dropped item. + } final long ownerId = readNumber(entityData).longValue(); if (ownerId == -1) { break; // No owner diff --git a/src/main/java/net/raphimc/viabedrock/protocol/storage/ChunkTracker.java b/src/main/java/net/raphimc/viabedrock/protocol/storage/ChunkTracker.java index 59c6a6f7b..3bf4268fb 100644 --- a/src/main/java/net/raphimc/viabedrock/protocol/storage/ChunkTracker.java +++ b/src/main/java/net/raphimc/viabedrock/protocol/storage/ChunkTracker.java @@ -48,6 +48,7 @@ import net.raphimc.viabedrock.api.chunk.section.BedrockChunkSection; import net.raphimc.viabedrock.api.chunk.section.BedrockChunkSectionImpl; import net.raphimc.viabedrock.api.model.BedrockBlockState; +import net.raphimc.viabedrock.api.model.BlockState; import net.raphimc.viabedrock.protocol.BedrockProtocol; import net.raphimc.viabedrock.protocol.ServerboundBedrockPackets; import net.raphimc.viabedrock.protocol.data.ProtocolConstants; @@ -217,25 +218,34 @@ public int getJavaBlockState(final BedrockChunkSection section, final int sectio remappedBlockState = ProtocolConstants.JAVA_AIR_ID; } - if (blockState0 != this.bedrockAirId() && blockPalettes.size() > 1) { + final int airId = this.bedrockAirId(); + if (blockState0 != airId && blockPalettes.size() > 1) { final int blockState1 = blockPalettes.get(1).idAt(sectionX, sectionY, sectionZ); - if (blockState1 != this.bedrockAirId()) { - if (CustomBlockTags.WATER.equals(blockStateRewriter.tag(blockState1))) { // Waterlogging - final int waterloggedBlockState = blockStateRewriter.waterlog(remappedBlockState); - if (waterloggedBlockState != -1) { - remappedBlockState = waterloggedBlockState; - } else { - ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Missing waterlogged block state: " + blockState0); - } - } else { - ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Invalid layer 2 block state. L1: " + blockState0 + ", L2: " + blockState1); - } + if (blockState1 != airId) { + return this.remapSecondBlockLayer(blockStateRewriter, blockState0, blockState1, remappedBlockState); } } return remappedBlockState; } + private int remapSecondBlockLayer(final BlockStateRewriter blockStateRewriter, final int blockState0, final int blockState1, final int javaBlockState) { + if (CustomBlockTags.WATER.equals(blockStateRewriter.tag(blockState1))) { + final int waterloggedBlockState = blockStateRewriter.waterlog(javaBlockState); + if (waterloggedBlockState != -1) { + return waterloggedBlockState; + } + ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Missing waterlogged block state: " + blockState0); + } else { + final BlockState primaryState = blockStateRewriter.blockState(blockState0); + // Snowlogged blocks are stored under snow in Bedrock. Keep the snow depth in Java's single block state. + if (primaryState == null || !primaryState.namespacedIdentifier().equals("minecraft:snow_layer") || blockStateRewriter.blockState(blockState1) == null) { + ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Invalid layer 2 block state. L1: " + blockState0 + ", L2: " + blockState1); + } + } + return javaBlockState; + } + public BedrockBlockEntity getBlockEntity(final BlockPosition blockPosition) { final BedrockChunk chunk = this.getChunk(blockPosition.x() >> 4, blockPosition.z() >> 4); if (chunk == null) { @@ -585,15 +595,10 @@ private Chunk remapChunk(final BedrockChunk chunk) { continue; } - if (CustomBlockTags.WATER.equals(blockStateRewriter.tag(blockState1))) { // Waterlogging - final int waterloggedBlockState = blockStateRewriter.waterlog(remappedBlockPalette.idAt(x, y, z)); - if (waterloggedBlockState != -1) { - remappedBlockPalette.setIdAt(x, y, z, waterloggedBlockState); - } else { - ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Missing waterlogged block state: " + blockState0); - } - } else { - ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Invalid layer 2 block state. L1: " + blockState0 + ", L2: " + blockState1); + final int javaBlockState = remappedBlockPalette.idAt(x, y, z); + final int combinedBlockState = this.remapSecondBlockLayer(blockStateRewriter, blockState0, blockState1, javaBlockState); + if (combinedBlockState != javaBlockState) { + remappedBlockPalette.setIdAt(x, y, z, combinedBlockState); } } } From 158ef4d4f26bfb373031b71eb296a33f1ee425b5 Mon Sep 17 00:00:00 2001 From: Jannis Guhl <128991638+guhlutions@users.noreply.github.com> Date: Fri, 13 Nov 2026 23:03:29 +0100 Subject: [PATCH 2/2] Keep dropped item ownership fix compatible with horse handling --- .../protocol/rewriter/EntityMetadataRewriter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java b/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java index 0eaef7d3a..d54c06677 100644 --- a/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java +++ b/src/main/java/net/raphimc/viabedrock/protocol/rewriter/EntityMetadataRewriter.java @@ -369,13 +369,13 @@ public static boolean rewrite(final UserConnection user, final Entity entity, fi } } case OWNER -> { - if (entity.javaType().is(EntityTypes26_3.ITEM)) { - break; // The Bedrock server enforces who can pick up a dropped item. - } final long ownerId = readNumber(entityData).longValue(); if (ownerId == -1) { break; // No owner } + if (entity.javaType().is(EntityTypes26_3.ITEM)) { + break; // The Bedrock server enforces who can pick up a dropped item. + } final Entity ownerEntity = entityTracker.getEntityByUid(ownerId); if (ownerEntity == null) { ViaBedrock.getPlatform().getLogger().log(Level.WARNING, "Failed to find owner entity with id " + ownerId + " for entity " + entity.type());