diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 11702e78a..e665a22ef 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -67,6 +67,7 @@ public final class BlockStateValues { private static final Int2IntMap SKULL_WALL_DIRECTIONS = new Int2IntOpenHashMap(); private static final Int2ByteMap SHULKERBOX_DIRECTIONS = new FixedInt2ByteMap(); private static final Int2IntMap WATER_LEVEL = new Int2IntOpenHashMap(); + private static final IntSet UPPER_DOORS = new IntOpenHashSet(); public static final int JAVA_AIR_ID = 0; @@ -219,6 +220,10 @@ public final class BlockStateValues { if (javaId.contains("_cauldron") && !javaId.contains("water_")) { NON_WATER_CAULDRONS.add(javaBlockState); } + + if (javaId.contains("_door[") && javaId.contains("half=upper")) { + UPPER_DOORS.add(javaBlockState); + } } /** @@ -498,6 +503,16 @@ public final class BlockStateValues { return WATER_LEVEL.getOrDefault(state, -1); } + /** + * Check if a block is the upper half of a door. + * + * @param state BlockState of the block + * @return True if the block is the upper half of a door + */ + public static boolean isUpperDoor(int state) { + return UPPER_DOORS.contains(state); + } + /** * Get the height of water from the block state * This is used in FishingHookEntity to create splash sounds when the hook hits the water. In addition, diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 114a7b6de..cc21e2d0a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -215,6 +215,14 @@ public class ChunkUtils { break; //No block will be a part of two classes } } + + if (BlockStateValues.isUpperDoor(blockState)) { + // Update the lower door block as Bedrock client doesn't like door to be closed from the top + // See https://github.com/GeyserMC/Geyser/issues/4358 + Vector3i belowDoorPosition = position.sub(0, 1, 0); + int belowDoorBlockState = session.getGeyser().getWorldManager().getBlockAt(session, belowDoorPosition.getX(), belowDoorPosition.getY(), belowDoorPosition.getZ()); + updateBlock(session, belowDoorBlockState, belowDoorPosition); + } } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) {