From beef01f3fc96befb0558b070c34dd04400fb4eec Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Fri, 17 May 2024 20:55:34 -0400 Subject: [PATCH] Pistons now use the new block stuff --- .../erosion/GeyserboundPacketHandlerImpl.java | 13 +- .../geysermc/geyser/level/WorldManager.java | 9 + .../geyser/level/block/BlockStateValues.java | 98 +-- .../geysermc/geyser/level/block/Blocks.java | 704 +++++++++--------- .../level/block/property/Properties.java | 2 +- .../geyser/level/block/type/Block.java | 86 +++ .../geyser/level/block/type/BlockState.java | 4 + .../level/block/type/CauldronBlock.java | 51 ++ .../geyser/level/block/type/ChestBlock.java | 52 ++ .../geyser/level/block/type/DoorBlock.java | 50 ++ .../block/type/FlowerPotBlock.java} | 74 +- .../geyser/level/block/type/LecternBlock.java | 61 ++ .../level/block/type/MovingPistonBlock.java | 42 ++ .../geyser/level/block/type/PistonBlock.java | 47 ++ .../geyser/level/block/type/SkullBlock.java | 54 ++ .../populator/BlockRegistryPopulator.java | 40 +- .../geyser/registry/type/BlockMapping.java | 15 +- .../geyser/registry/type/BlockMappings.java | 5 + .../geyser/session/cache/TagCache.java | 12 - .../geyser/session/cache/WorldCache.java | 2 +- ...a => BedrockChunkWantsBlockEntityTag.java} | 30 +- .../block/entity/BedrockOnlyBlockEntity.java | 82 -- .../DoubleChestBlockEntityTranslator.java | 21 +- .../level/block/entity/PistonBlockEntity.java | 85 +-- .../BedrockBlockPickRequestTranslator.java | 4 +- .../java/level/JavaBlockEventTranslator.java | 22 +- .../JavaLevelChunkWithLightTranslator.java | 19 +- .../geyser/util/BlockEntityUtils.java | 12 - .../org/geysermc/geyser/util/ChunkUtils.java | 111 +-- 29 files changed, 978 insertions(+), 829 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java rename core/src/main/java/org/geysermc/geyser/{translator/level/block/entity/FlowerPotBlockEntityTranslator.java => level/block/type/FlowerPotBlock.java} (60%) create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java create mode 100644 core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java rename core/src/main/java/org/geysermc/geyser/translator/level/block/entity/{PistonBlockEntityTranslator.java => BedrockChunkWantsBlockEntityTag.java} (59%) delete mode 100644 core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java index b76dc0b85..6e22fd430 100644 --- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -26,11 +26,12 @@ package org.geysermc.geyser.erosion; import io.netty.channel.Channel; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; import org.cloudburstmc.math.vector.Vector3i; @@ -44,6 +45,7 @@ import org.geysermc.erosion.packet.backendbound.BackendboundPacket; import org.geysermc.erosion.packet.geyserbound.*; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; @@ -153,9 +155,10 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke var stream = packet.getAttachedBlocks() .object2IntEntrySet() .stream() - .filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend)); - Object2IntMap attachedBlocks = new Object2IntArrayMap<>(); - stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue())); + .map(entry -> Pair.of(entry.getKey(), BlockState.of(entry.getIntValue()))) + .filter(pair -> BlockStateValues.canPistonMoveBlock(pair.value(), isExtend)); + Object2ObjectMap attachedBlocks = new Object2ObjectOpenHashMap<>(); + stream.forEach(pair -> attachedBlocks.put(pair.key(), pair.value())); session.executeInEventLoop(() -> { PistonCache pistonCache = session.getPistonCache(); diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index cd6c9e824..5edce21dc 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -33,6 +33,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.erosion.util.BlockPositionIterator; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent; @@ -58,6 +59,14 @@ import java.util.function.Function; */ public abstract class WorldManager { + public final BlockState blockAt(GeyserSession session, Vector3i vector3i) { + return BlockState.of(this.getBlockAt(session, vector3i)); + } + + public BlockState blockAt(GeyserSession session, int x, int y, int z) { + return BlockState.of(this.getBlockAt(session, x, y, z)); + } + /** * Gets the Java block state at the specified location * 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 e2a2cb5eb..a64e5c1c8 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 @@ -29,12 +29,14 @@ import com.fasterxml.jackson.databind.JsonNode; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.PistonBlock; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; -import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntityTranslator; import org.geysermc.geyser.util.collection.FixedInt2ByteMap; import org.geysermc.geyser.util.collection.FixedInt2IntMap; import org.geysermc.geyser.util.collection.LecternHasBookMap; @@ -229,28 +231,6 @@ public final class BlockStateValues { return BANNER_COLORS.getOrDefault(state, -1); } - /** - * Bed colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte color that Bedrock can use - Bedrock needs a byte in the final tag. - * - * @param state BlockState of the block - * @return Bed color byte or -1 if no color - */ - public static byte getBedColor(int state) { - return BED_COLORS.getOrDefault(state, (byte) -1); - } - - /** - * The brush progress of suspicious sand/gravel is not sent by the java server when it updates the block entity. - * Although brush progress is part of the bedrock block state, it must be included in the block entity update. - * - * @param state BlockState of the block - * @return brush progress or 0 if the lookup failed - */ - public static int getBrushProgress(int state) { - return BRUSH_PROGRESS.getOrDefault(state, 0); - } - /** * @return if this Java block state is a non-empty non-water cauldron */ @@ -341,18 +321,6 @@ public final class BlockStateValues { return PISTON_HEADS.getOrDefault(direction, Block.JAVA_AIR_ID); } - /** - * Check if a block is a minecraft:moving_piston - * This is used in ChunkUtils to prevent them from being placed as it causes - * pistons to flicker and it is not needed - * - * @param state Block state of the block - * @return True if the block is a moving_piston - */ - public static boolean isMovingPiston(int state) { - return MOVING_PISTONS.contains(state); - } - /** * This is used in GeyserPistonEvents.java and accepts minecraft:piston, * minecraft:sticky_piston, and minecraft:moving_piston. @@ -371,8 +339,9 @@ public final class BlockStateValues { * @param state The block state * @return True if the block sticks to adjacent blocks */ - public static boolean isBlockSticky(int state) { - return state == JAVA_SLIME_BLOCK_ID || state == JAVA_HONEY_BLOCK_ID; + public static boolean isBlockSticky(BlockState state) { + Block block = state.block(); + return block == Blocks.SLIME_BLOCK || block == Blocks.HONEY_BLOCK; } /** @@ -382,13 +351,13 @@ public final class BlockStateValues { * @param stateB The block state of block b * @return True if the blocks are attached to each other */ - public static boolean isBlockAttached(int stateA, int stateB) { + public static boolean isBlockAttached(BlockState stateA, BlockState stateB) { boolean aSticky = isBlockSticky(stateA); boolean bSticky = isBlockSticky(stateB); if (aSticky && bSticky) { // Only matching sticky blocks are attached together // Honey + Honey & Slime + Slime - return stateA == stateB; + return stateA.block() == stateB.block(); } return aSticky || bSticky; } @@ -397,27 +366,30 @@ public final class BlockStateValues { * @param state The block state of the block * @return true if a piston can break the block */ - public static boolean canPistonDestroyBlock(int state) { - return BlockRegistries.JAVA_BLOCKS.getOrDefault(state, BlockMapping.DEFAULT).getPistonBehavior() == PistonBehavior.DESTROY; + public static boolean canPistonDestroyBlock(BlockState state) { + return state.block().pushReaction() == PistonBehavior.DESTROY; } - public static boolean canPistonMoveBlock(int javaId, boolean isPushing) { - if (javaId == Block.JAVA_AIR_ID) { + public static boolean canPistonMoveBlock(BlockState state, boolean isPushing) { + Block block = state.block(); + if (block == Blocks.AIR) { return true; } - // Pistons can only be moved if they aren't extended - if (PistonBlockEntityTranslator.isBlock(javaId)) { - return !PISTON_VALUES.get(javaId); - } - BlockMapping block = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaId, BlockMapping.DEFAULT); - // Bedrock, End portal frames, etc. can't be moved - if (block.getHardness() == -1.0d) { + if (block == Blocks.OBSIDIAN || block == Blocks.CRYING_OBSIDIAN || block == Blocks.RESPAWN_ANCHOR || block == Blocks.REINFORCED_DEEPSLATE) { // Hardcoded as of 1.20.5 return false; } - return switch (block.getPistonBehavior()) { + // Pistons can only be moved if they aren't extended + if (block instanceof PistonBlock) { + return !state.getValue(Properties.EXTENDED); + } + // Bedrock, End portal frames, etc. can't be moved + if (block.destroyTime() == -1.0f) { + return false; + } + return switch (block.pushReaction()) { case BLOCK, DESTROY -> false; case PUSH_ONLY -> isPushing; // Glazed terracotta can only be pushed - default -> !block.isBlockEntity(); // Pistons can't move block entities + default -> !block.hasBlockEntity(); // Pistons can't move block entities }; } @@ -443,17 +415,6 @@ public final class BlockStateValues { return SKULL_ROTATIONS.getOrDefault(state, (byte) -1); } - /** - * As of Java 1.20.2: - * Skull powered states are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * - * @param state BlockState of the block - * @return true if this skull is currently being powered. - */ - public static boolean isSkullPowered(int state) { - return SKULL_POWERED.contains(state); - } - /** * Skull rotations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. * This gives a integer rotation that Bedrock can use. @@ -464,17 +425,6 @@ public final class BlockStateValues { return SKULL_WALL_DIRECTIONS; } - /** - * Shulker box directions are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a byte direction that Bedrock can use. - * - * @param state BlockState of the block - * @return Shulker direction value or -1 if no value - */ - public static byte getShulkerBoxDirection(int state) { - return SHULKERBOX_DIRECTIONS.getOrDefault(state, (byte) -1); - } - /** * Get the level of water from the block state. * diff --git a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java index 1f9c9c162..142708dd9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java @@ -25,11 +25,11 @@ package org.geysermc.geyser.level.block; -import org.geysermc.geyser.level.block.type.BannerBlock; -import org.geysermc.geyser.level.block.type.BedBlock; -import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.type.*; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; import static org.geysermc.geyser.level.block.property.Properties.*; @@ -62,36 +62,36 @@ public final class Blocks { public static final Block MANGROVE_PLANKS = register(new Block("mangrove_planks", builder().destroyTime(2.0f))); public static final Block BAMBOO_PLANKS = register(new Block("bamboo_planks", builder().destroyTime(2.0f))); public static final Block BAMBOO_MOSAIC = register(new Block("bamboo_mosaic", builder().destroyTime(2.0f))); - public static final Block OAK_SAPLING = register(new Block("oak_sapling", builder() + public static final Block OAK_SAPLING = register(new Block("oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder() + public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder() + public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder() + public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder() + public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder() + public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder() + public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) .intState(STAGE, 0, 1))); - public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder() + public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_4, 0, 4) .booleanState(HANGING) .intState(STAGE, 0, 1) .booleanState(WATERLOGGED))); public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f))); - public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f) + public static final Block WATER = register(new Block("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); - public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f) + public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) .intState(LEVEL, 0, 15))); public static final Block SAND = register(new Block("sand", builder().destroyTime(0.5f))); - public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity().destroyTime(0.25f) + public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .intState(DUSTED, 0, 3))); public static final Block RED_SAND = register(new Block("red_sand", builder().destroyTime(0.5f))); public static final Block GRAVEL = register(new Block("gravel", builder().destroyTime(0.6f))); - public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity().destroyTime(0.25f) + public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) .intState(DUSTED, 0, 3))); public static final Block GOLD_ORE = register(new Block("gold_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DEEPSLATE_GOLD_ORE = register(new Block("deepslate_gold_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); @@ -172,43 +172,43 @@ public final class Blocks { .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f) + public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f) + public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f) + public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f) + public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f) + public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f) + public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f) + public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f) + public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f) + public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); - public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f) + public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(DISTANCE, 1, 7) .booleanState(PERSISTENT) .booleanState(WATERLOGGED))); @@ -228,67 +228,67 @@ public final class Blocks { .enumState(NOTEBLOCK_INSTRUMENT, "harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling", "zombie", "skeleton", "creeper", "dragon", "wither_skeleton", "piglin", "custom_head") .intState(NOTE, 0, 24) .booleanState(POWERED))); - public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f) + public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f) + public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f) + public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f) + public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f) + public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f) + public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f) + public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f) + public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f) + public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f) + public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f) + public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); - public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f) + public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(OCCUPIED) .enumState(BED_PART, "head", "foot"))); @@ -300,20 +300,20 @@ public final class Blocks { .booleanState(POWERED) .enumState(RAIL_SHAPE_STRAIGHT, "north_south", "east_west", "ascending_east", "ascending_west", "ascending_north", "ascending_south") .booleanState(WATERLOGGED))); - public static final Block STICKY_PISTON = register(new Block("sticky_piston", builder().destroyTime(1.5f) + public static final Block STICKY_PISTON = register(new PistonBlock("sticky_piston", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) .booleanState(EXTENDED) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block COBWEB = register(new Block("cobweb", builder().requiresCorrectToolForDrops().destroyTime(4.0f))); - public static final Block SHORT_GRASS = register(new Block("short_grass", builder())); - public static final Block FERN = register(new Block("fern", builder())); - public static final Block DEAD_BUSH = register(new Block("dead_bush", builder())); - public static final Block SEAGRASS = register(new Block("seagrass", builder())); - public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder() + public static final Block COBWEB = register(new Block("cobweb", builder().requiresCorrectToolForDrops().destroyTime(4.0f).pushReaction(PistonBehavior.DESTROY))); + public static final Block SHORT_GRASS = register(new Block("short_grass", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block FERN = register(new Block("fern", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block DEAD_BUSH = register(new Block("dead_bush", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block SEAGRASS = register(new Block("seagrass", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PISTON = register(new Block("piston", builder().destroyTime(1.5f) + public static final Block PISTON = register(new PistonBlock("piston", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) .booleanState(EXTENDED) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block PISTON_HEAD = register(new Block("piston_head", builder().destroyTime(1.5f) + public static final Block PISTON_HEAD = register(new Block("piston_head", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(SHORT) .enumState(PISTON_TYPE, "normal", "sticky"))); @@ -333,25 +333,25 @@ public final class Blocks { public static final Block GREEN_WOOL = register(new Block("green_wool", builder().destroyTime(0.8f))); public static final Block RED_WOOL = register(new Block("red_wool", builder().destroyTime(0.8f))); public static final Block BLACK_WOOL = register(new Block("black_wool", builder().destroyTime(0.8f))); - public static final Block MOVING_PISTON = register(new Block("moving_piston", builder().setBlockEntity().destroyTime(-1.0f) + public static final Block MOVING_PISTON = register(new MovingPistonBlock("moving_piston", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .enumState(PISTON_TYPE, "normal", "sticky"))); - public static final Block DANDELION = register(new Block("dandelion", builder())); - public static final Block TORCHFLOWER = register(new Block("torchflower", builder())); - public static final Block POPPY = register(new Block("poppy", builder())); - public static final Block BLUE_ORCHID = register(new Block("blue_orchid", builder())); - public static final Block ALLIUM = register(new Block("allium", builder())); - public static final Block AZURE_BLUET = register(new Block("azure_bluet", builder())); - public static final Block RED_TULIP = register(new Block("red_tulip", builder())); - public static final Block ORANGE_TULIP = register(new Block("orange_tulip", builder())); - public static final Block WHITE_TULIP = register(new Block("white_tulip", builder())); - public static final Block PINK_TULIP = register(new Block("pink_tulip", builder())); - public static final Block OXEYE_DAISY = register(new Block("oxeye_daisy", builder())); - public static final Block CORNFLOWER = register(new Block("cornflower", builder())); - public static final Block WITHER_ROSE = register(new Block("wither_rose", builder())); - public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder())); - public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder())); - public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder())); + public static final Block DANDELION = register(new Block("dandelion", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block TORCHFLOWER = register(new Block("torchflower", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POPPY = register(new Block("poppy", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block BLUE_ORCHID = register(new Block("blue_orchid", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block ALLIUM = register(new Block("allium", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block AZURE_BLUET = register(new Block("azure_bluet", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block RED_TULIP = register(new Block("red_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block ORANGE_TULIP = register(new Block("orange_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block WHITE_TULIP = register(new Block("white_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block PINK_TULIP = register(new Block("pink_tulip", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block OXEYE_DAISY = register(new Block("oxeye_daisy", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block CORNFLOWER = register(new Block("cornflower", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block WITHER_ROSE = register(new Block("wither_rose", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block LILY_OF_THE_VALLEY = register(new Block("lily_of_the_valley", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block BROWN_MUSHROOM = register(new Block("brown_mushroom", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block RED_MUSHROOM = register(new Block("red_mushroom", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block GOLD_BLOCK = register(new Block("gold_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block IRON_BLOCK = register(new Block("iron_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BRICKS = register(new Block("bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); @@ -368,28 +368,28 @@ public final class Blocks { .booleanState(CHISELED_BOOKSHELF_SLOT_5_OCCUPIED))); public static final Block MOSSY_COBBLESTONE = register(new Block("mossy_cobblestone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block OBSIDIAN = register(new Block("obsidian", builder().requiresCorrectToolForDrops().destroyTime(50.0f))); - public static final Block TORCH = register(new Block("torch", builder())); - public static final Block WALL_TORCH = register(new Block("wall_torch", builder() + public static final Block TORCH = register(new Block("torch", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block WALL_TORCH = register(new Block("wall_torch", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block FIRE = register(new Block("fire", builder() + public static final Block FIRE = register(new Block("fire", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 15) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block SOUL_FIRE = register(new Block("soul_fire", builder())); + public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SPAWNER = register(new Block("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder().destroyTime(2.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(HALF, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CHEST = register(new Block("chest", builder().setBlockEntity().destroyTime(2.5f) + public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, "single", "left", "right") + .enumState(CHEST_TYPE, ChestType.VALUES) .booleanState(WATERLOGGED))); - public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder() + public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder().pushReaction(PistonBehavior.DESTROY) .enumState(EAST_REDSTONE, "up", "side", "none") .enumState(NORTH_REDSTONE, "up", "side", "none") .intState(POWER, 0, 15) @@ -399,7 +399,7 @@ public final class Blocks { public static final Block DEEPSLATE_DIAMOND_ORE = register(new Block("deepslate_diamond_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block DIAMOND_BLOCK = register(new Block("diamond_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block CRAFTING_TABLE = register(new Block("crafting_table", builder().destroyTime(2.5f))); - public static final Block WHEAT = register(new Block("wheat", builder() + public static final Block WHEAT = register(new Block("wheat", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) .intState(MOISTURE, 0, 7))); @@ -433,13 +433,13 @@ public final class Blocks { public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15) .booleanState(WATERLOGGED))); - public static final Block OAK_DOOR = register(new Block("oak_door", builder().destroyTime(3.0f) + public static final Block OAK_DOOR = register(new DoorBlock("oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block LADDER = register(new Block("ladder", builder().destroyTime(0.4f) + public static final Block LADDER = register(new Block("ladder", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); public static final Block RAIL = register(new Block("rail", builder().destroyTime(0.7f) @@ -554,57 +554,57 @@ public final class Blocks { public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f) + public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block IRON_DOOR = register(new Block("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block IRON_DOOR = register(new DoorBlock("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f) + public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f) + public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f) + public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f) + public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f) + public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f) + public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder().destroyTime(0.5f) + public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder().destroyTime(0.5f) + public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f) + public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .booleanState(LIT))); public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f) .booleanState(LIT))); - public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder() + public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder() + public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(LIT))); - public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f) + public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SNOW = register(new Block("snow", builder().requiresCorrectToolForDrops().destroyTime(0.1f) + public static final Block SNOW = register(new Block("snow", builder().requiresCorrectToolForDrops().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(LAYERS, 1, 8))); public static final Block ICE = register(new Block("ice", builder().destroyTime(0.5f))); public static final Block SNOW_BLOCK = register(new Block("snow_block", builder().requiresCorrectToolForDrops().destroyTime(0.2f))); - public static final Block CACTUS = register(new Block("cactus", builder().destroyTime(0.4f) + public static final Block CACTUS = register(new Block("cactus", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 15))); public static final Block CLAY = register(new Block("clay", builder().destroyTime(0.6f))); - public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder() + public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_15, 0, 15))); public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f) .booleanState(HAS_RECORD))); @@ -621,19 +621,19 @@ public final class Blocks { .enumState(AXIS, Axis.VALUES))); public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f) .enumState(AXIS, Axis.VALUES))); - public static final Block SOUL_TORCH = register(new Block("soul_torch", builder())); - public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder() + public static final Block SOUL_TORCH = register(new Block("soul_torch", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GLOWSTONE = register(new Block("glowstone", builder().destroyTime(0.3f))); - public static final Block NETHER_PORTAL = register(new Block("nether_portal", builder().destroyTime(-1.0f) + public static final Block NETHER_PORTAL = register(new Block("nether_portal", builder().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .enumState(HORIZONTAL_AXIS, Axis.X, Axis.Z))); - public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder().destroyTime(1.0f) + public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block JACK_O_LANTERN = register(new Block("jack_o_lantern", builder().destroyTime(1.0f) + public static final Block JACK_O_LANTERN = register(new Block("jack_o_lantern", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f) + public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(BITES, 0, 6))); - public static final Block REPEATER = register(new Block("repeater", builder() + public static final Block REPEATER = register(new Block("repeater", builder().pushReaction(PistonBehavior.DESTROY) .intState(DELAY, 1, 4) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(LOCKED) @@ -756,23 +756,23 @@ public final class Blocks { .booleanState(SOUTH) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block PUMPKIN = register(new Block("pumpkin", builder().destroyTime(1.0f))); - public static final Block MELON = register(new Block("melon", builder().destroyTime(1.0f))); - public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder() + public static final Block PUMPKIN = register(new Block("pumpkin", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); + public static final Block MELON = register(new Block("melon", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); + public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block ATTACHED_MELON_STEM = register(new Block("attached_melon_stem", builder() + public static final Block ATTACHED_MELON_STEM = register(new Block("attached_melon_stem", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder() + public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block MELON_STEM = register(new Block("melon_stem", builder() + public static final Block MELON_STEM = register(new Block("melon_stem", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f) + public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f) + public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -802,7 +802,7 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) .booleanState(SNOWY))); - public static final Block LILY_PAD = register(new Block("lily_pad", builder())); + public static final Block LILY_PAD = register(new Block("lily_pad", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block NETHER_BRICKS = register(new Block("nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block NETHER_BRICK_FENCE = register(new Block("nether_brick_fence", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .booleanState(EAST) @@ -815,28 +815,28 @@ public final class Blocks { .enumState(HALF, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block NETHER_WART = register(new Block("nether_wart", builder() + public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 3))); public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f) .booleanState(HAS_BOTTLE_0) .booleanState(HAS_BOTTLE_1) .booleanState(HAS_BOTTLE_2))); - public static final Block CAULDRON = register(new Block("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); + public static final Block CAULDRON = register(new CauldronBlock("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block WATER_CAULDRON = register(new Block("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); public static final Block LAVA_CAULDRON = register(new Block("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block POWDER_SNOW_CAULDRON = register(new Block("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .intState(LEVEL_CAULDRON, 1, 3))); - public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f))); + public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder().destroyTime(-1.0f) .booleanState(EYE) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block END_STONE = register(new Block("end_stone", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); - public static final Block DRAGON_EGG = register(new Block("dragon_egg", builder().destroyTime(3.0f))); + public static final Block DRAGON_EGG = register(new Block("dragon_egg", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY))); public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder().destroyTime(0.3f) .booleanState(LIT))); - public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f) + public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_2, 0, 2) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block SANDSTONE_STAIRS = register(new Block("sandstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(0.8f) @@ -849,11 +849,11 @@ public final class Blocks { public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(22.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block TRIPWIRE_HOOK = register(new Block("tripwire_hook", builder() + public static final Block TRIPWIRE_HOOK = register(new Block("tripwire_hook", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(ATTACHED) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block TRIPWIRE = register(new Block("tripwire", builder() + public static final Block TRIPWIRE = register(new Block("tripwire", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(ATTACHED) .booleanState(DISARMED) .booleanState(EAST) @@ -895,131 +895,131 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block FLOWER_POT = register(new Block("flower_pot", builder())); - public static final Block POTTED_TORCHFLOWER = register(new Block("potted_torchflower", builder())); - public static final Block POTTED_OAK_SAPLING = register(new Block("potted_oak_sapling", builder())); - public static final Block POTTED_SPRUCE_SAPLING = register(new Block("potted_spruce_sapling", builder())); - public static final Block POTTED_BIRCH_SAPLING = register(new Block("potted_birch_sapling", builder())); - public static final Block POTTED_JUNGLE_SAPLING = register(new Block("potted_jungle_sapling", builder())); - public static final Block POTTED_ACACIA_SAPLING = register(new Block("potted_acacia_sapling", builder())); - public static final Block POTTED_CHERRY_SAPLING = register(new Block("potted_cherry_sapling", builder())); - public static final Block POTTED_DARK_OAK_SAPLING = register(new Block("potted_dark_oak_sapling", builder())); - public static final Block POTTED_MANGROVE_PROPAGULE = register(new Block("potted_mangrove_propagule", builder())); - public static final Block POTTED_FERN = register(new Block("potted_fern", builder())); - public static final Block POTTED_DANDELION = register(new Block("potted_dandelion", builder())); - public static final Block POTTED_POPPY = register(new Block("potted_poppy", builder())); - public static final Block POTTED_BLUE_ORCHID = register(new Block("potted_blue_orchid", builder())); - public static final Block POTTED_ALLIUM = register(new Block("potted_allium", builder())); - public static final Block POTTED_AZURE_BLUET = register(new Block("potted_azure_bluet", builder())); - public static final Block POTTED_RED_TULIP = register(new Block("potted_red_tulip", builder())); - public static final Block POTTED_ORANGE_TULIP = register(new Block("potted_orange_tulip", builder())); - public static final Block POTTED_WHITE_TULIP = register(new Block("potted_white_tulip", builder())); - public static final Block POTTED_PINK_TULIP = register(new Block("potted_pink_tulip", builder())); - public static final Block POTTED_OXEYE_DAISY = register(new Block("potted_oxeye_daisy", builder())); - public static final Block POTTED_CORNFLOWER = register(new Block("potted_cornflower", builder())); - public static final Block POTTED_LILY_OF_THE_VALLEY = register(new Block("potted_lily_of_the_valley", builder())); - public static final Block POTTED_WITHER_ROSE = register(new Block("potted_wither_rose", builder())); - public static final Block POTTED_RED_MUSHROOM = register(new Block("potted_red_mushroom", builder())); - public static final Block POTTED_BROWN_MUSHROOM = register(new Block("potted_brown_mushroom", builder())); - public static final Block POTTED_DEAD_BUSH = register(new Block("potted_dead_bush", builder())); - public static final Block POTTED_CACTUS = register(new Block("potted_cactus", builder())); - public static final Block CARROTS = register(new Block("carrots", builder() + public static final Block FLOWER_POT = register(new FlowerPotBlock("flower_pot", AIR, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_TORCHFLOWER = register(new FlowerPotBlock("potted_torchflower", TORCHFLOWER, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_OAK_SAPLING = register(new FlowerPotBlock("potted_oak_sapling", OAK_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_SPRUCE_SAPLING = register(new FlowerPotBlock("potted_spruce_sapling", SPRUCE_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BIRCH_SAPLING = register(new FlowerPotBlock("potted_birch_sapling", BIRCH_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_JUNGLE_SAPLING = register(new FlowerPotBlock("potted_jungle_sapling", JUNGLE_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_ACACIA_SAPLING = register(new FlowerPotBlock("potted_acacia_sapling", ACACIA_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CHERRY_SAPLING = register(new FlowerPotBlock("potted_cherry_sapling", CHERRY_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_DARK_OAK_SAPLING = register(new FlowerPotBlock("potted_dark_oak_sapling", DARK_OAK_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_MANGROVE_PROPAGULE = register(new FlowerPotBlock("potted_mangrove_propagule", MANGROVE_PROPAGULE, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_FERN = register(new FlowerPotBlock("potted_fern", FERN, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_DANDELION = register(new FlowerPotBlock("potted_dandelion", DANDELION, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_POPPY = register(new FlowerPotBlock("potted_poppy", POPPY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BLUE_ORCHID = register(new FlowerPotBlock("potted_blue_orchid", BLUE_ORCHID, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_ALLIUM = register(new FlowerPotBlock("potted_allium", ALLIUM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_AZURE_BLUET = register(new FlowerPotBlock("potted_azure_bluet", AZURE_BLUET, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_RED_TULIP = register(new FlowerPotBlock("potted_red_tulip", RED_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_ORANGE_TULIP = register(new FlowerPotBlock("potted_orange_tulip", ORANGE_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WHITE_TULIP = register(new FlowerPotBlock("potted_white_tulip", WHITE_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_PINK_TULIP = register(new FlowerPotBlock("potted_pink_tulip", PINK_TULIP, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_OXEYE_DAISY = register(new FlowerPotBlock("potted_oxeye_daisy", OXEYE_DAISY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CORNFLOWER = register(new FlowerPotBlock("potted_cornflower", CORNFLOWER, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_LILY_OF_THE_VALLEY = register(new FlowerPotBlock("potted_lily_of_the_valley", LILY_OF_THE_VALLEY, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WITHER_ROSE = register(new FlowerPotBlock("potted_wither_rose", WITHER_ROSE, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_RED_MUSHROOM = register(new FlowerPotBlock("potted_red_mushroom", RED_MUSHROOM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_BROWN_MUSHROOM = register(new FlowerPotBlock("potted_brown_mushroom", BROWN_MUSHROOM, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_DEAD_BUSH = register(new FlowerPotBlock("potted_dead_bush", DEAD_BUSH, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CACTUS = register(new FlowerPotBlock("potted_cactus", CACTUS, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block CARROTS = register(new Block("carrots", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block POTATOES = register(new Block("potatoes", builder() + public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_7, 0, 7))); - public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f) + public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f) + public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f) + public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f) + public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f) + public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f) + public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f) + public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f) + public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f) + public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block SKELETON_SKULL = register(new Block("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block SKELETON_WALL_SKULL = register(new Block("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block SKELETON_WALL_SKULL = register(new SkullBlock("skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block WITHER_SKELETON_SKULL = register(new Block("wither_skeleton_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block WITHER_SKELETON_WALL_SKULL = register(new Block("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f) + public static final Block WITHER_SKELETON_WALL_SKULL = register(new SkullBlock("wither_skeleton_wall_skull", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ZOMBIE_HEAD = register(new Block("zombie_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block ZOMBIE_WALL_HEAD = register(new Block("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block ZOMBIE_WALL_HEAD = register(new SkullBlock("zombie_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PLAYER_HEAD = register(new Block("player_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PLAYER_WALL_HEAD = register(new Block("player_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PLAYER_WALL_HEAD = register(new SkullBlock("player_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CREEPER_HEAD = register(new Block("creeper_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block CREEPER_WALL_HEAD = register(new Block("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block CREEPER_WALL_HEAD = register(new SkullBlock("creeper_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block DRAGON_HEAD = register(new Block("dragon_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block DRAGON_WALL_HEAD = register(new Block("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block DRAGON_WALL_HEAD = register(new SkullBlock("dragon_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block PIGLIN_HEAD = register(new Block("piglin_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED) .intState(ROTATION_16, 0, 15))); - public static final Block PIGLIN_WALL_HEAD = register(new Block("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f) + public static final Block PIGLIN_WALL_HEAD = register(new SkullBlock("piglin_wall_head", builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block TRAPPED_CHEST = register(new Block("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) + public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, "single", "left", "right") + .enumState(CHEST_TYPE, ChestType.VALUES) .booleanState(WATERLOGGED))); - public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(POWER, 0, 15))); - public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(POWER, 0, 15))); - public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity() + public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(MODE_COMPARATOR, "compare", "subtract") .booleanState(POWERED))); @@ -1190,7 +1190,7 @@ public final class Blocks { .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); public static final Block SLIME_BLOCK = register(new Block("slime_block", builder())); - public static final Block BARRIER = register(new Block("barrier", builder().destroyTime(-1.0f) + public static final Block BARRIER = register(new Block("barrier", builder().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) .booleanState(WATERLOGGED))); public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) .intState(LEVEL, 0, 15) @@ -1250,17 +1250,17 @@ public final class Blocks { public static final Block TERRACOTTA = register(new Block("terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block COAL_BLOCK = register(new Block("coal_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block PACKED_ICE = register(new Block("packed_ice", builder().destroyTime(0.5f))); - public static final Block SUNFLOWER = register(new Block("sunflower", builder() + public static final Block SUNFLOWER = register(new Block("sunflower", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block LILAC = register(new Block("lilac", builder() + public static final Block LILAC = register(new Block("lilac", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block ROSE_BUSH = register(new Block("rose_bush", builder() + public static final Block ROSE_BUSH = register(new Block("rose_bush", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PEONY = register(new Block("peony", builder() + public static final Block PEONY = register(new Block("peony", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block TALL_GRASS = register(new Block("tall_grass", builder() + public static final Block TALL_GRASS = register(new Block("tall_grass", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block LARGE_FERN = register(new Block("large_fern", builder() + public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f) .intState(ROTATION_16, 0, 15))); @@ -1498,49 +1498,49 @@ public final class Blocks { .booleanState(SOUTH) .booleanState(WATERLOGGED) .booleanState(WEST))); - public static final Block SPRUCE_DOOR = register(new Block("spruce_door", builder().destroyTime(3.0f) + public static final Block SPRUCE_DOOR = register(new DoorBlock("spruce_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BIRCH_DOOR = register(new Block("birch_door", builder().destroyTime(3.0f) + public static final Block BIRCH_DOOR = register(new DoorBlock("birch_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block JUNGLE_DOOR = register(new Block("jungle_door", builder().destroyTime(3.0f) + public static final Block JUNGLE_DOOR = register(new DoorBlock("jungle_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block ACACIA_DOOR = register(new Block("acacia_door", builder().destroyTime(3.0f) + public static final Block ACACIA_DOOR = register(new DoorBlock("acacia_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block CHERRY_DOOR = register(new Block("cherry_door", builder().destroyTime(3.0f) + public static final Block CHERRY_DOOR = register(new DoorBlock("cherry_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block DARK_OAK_DOOR = register(new Block("dark_oak_door", builder().destroyTime(3.0f) + public static final Block DARK_OAK_DOOR = register(new DoorBlock("dark_oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block MANGROVE_DOOR = register(new Block("mangrove_door", builder().destroyTime(3.0f) + public static final Block MANGROVE_DOOR = register(new DoorBlock("mangrove_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block BAMBOO_DOOR = register(new Block("bamboo_door", builder().destroyTime(3.0f) + public static final Block BAMBOO_DOOR = register(new DoorBlock("bamboo_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -1548,14 +1548,14 @@ public final class Blocks { .booleanState(POWERED))); public static final Block END_ROD = register(new Block("end_rod", builder() .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder().destroyTime(0.4f) + public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) .booleanState(SOUTH) .booleanState(UP) .booleanState(WEST))); - public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f) + public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_5, 0, 5))); public static final Block PURPUR_BLOCK = register(new Block("purpur_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block PURPUR_PILLAR = register(new Block("purpur_pillar", builder().requiresCorrectToolForDrops().destroyTime(1.5f) @@ -1566,17 +1566,17 @@ public final class Blocks { .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); public static final Block END_STONE_BRICKS = register(new Block("end_stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); - public static final Block TORCHFLOWER_CROP = register(new Block("torchflower_crop", builder() + public static final Block TORCHFLOWER_CROP = register(new Block("torchflower_crop", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_1, 0, 1))); - public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder() + public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_4, 0, 4) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder() + public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder().pushReaction(PistonBehavior.DESTROY) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower"))); - public static final Block BEETROOTS = register(new Block("beetroots", builder() + public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 3))); public static final Block DIRT_PATH = register(new Block("dirt_path", builder().destroyTime(0.65f))); - public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity().destroyTime(-1.0f))); + public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f) .booleanState(CONDITIONAL) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); @@ -1590,75 +1590,75 @@ public final class Blocks { public static final Block RED_NETHER_BRICKS = register(new Block("red_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block BONE_BLOCK = register(new Block("bone_block", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); - public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder())); + public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block OBSERVER = register(new Block("observer", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(POWERED))); - public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f) + public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); - public static final Block WHITE_GLAZED_TERRACOTTA = register(new Block("white_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block WHITE_GLAZED_TERRACOTTA = register(new Block("white_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block ORANGE_GLAZED_TERRACOTTA = register(new Block("orange_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block ORANGE_GLAZED_TERRACOTTA = register(new Block("orange_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block MAGENTA_GLAZED_TERRACOTTA = register(new Block("magenta_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block MAGENTA_GLAZED_TERRACOTTA = register(new Block("magenta_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LIGHT_BLUE_GLAZED_TERRACOTTA = register(new Block("light_blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block LIGHT_BLUE_GLAZED_TERRACOTTA = register(new Block("light_blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block YELLOW_GLAZED_TERRACOTTA = register(new Block("yellow_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block YELLOW_GLAZED_TERRACOTTA = register(new Block("yellow_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LIME_GLAZED_TERRACOTTA = register(new Block("lime_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block LIME_GLAZED_TERRACOTTA = register(new Block("lime_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block PINK_GLAZED_TERRACOTTA = register(new Block("pink_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block PINK_GLAZED_TERRACOTTA = register(new Block("pink_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block GRAY_GLAZED_TERRACOTTA = register(new Block("gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block GRAY_GLAZED_TERRACOTTA = register(new Block("gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LIGHT_GRAY_GLAZED_TERRACOTTA = register(new Block("light_gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block LIGHT_GRAY_GLAZED_TERRACOTTA = register(new Block("light_gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block CYAN_GLAZED_TERRACOTTA = register(new Block("cyan_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block CYAN_GLAZED_TERRACOTTA = register(new Block("cyan_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block PURPLE_GLAZED_TERRACOTTA = register(new Block("purple_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block PURPLE_GLAZED_TERRACOTTA = register(new Block("purple_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block BLUE_GLAZED_TERRACOTTA = register(new Block("blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block BLUE_GLAZED_TERRACOTTA = register(new Block("blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block BROWN_GLAZED_TERRACOTTA = register(new Block("brown_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block BROWN_GLAZED_TERRACOTTA = register(new Block("brown_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block GREEN_GLAZED_TERRACOTTA = register(new Block("green_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block GREEN_GLAZED_TERRACOTTA = register(new Block("green_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block RED_GLAZED_TERRACOTTA = register(new Block("red_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block RED_GLAZED_TERRACOTTA = register(new Block("red_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block BLACK_GLAZED_TERRACOTTA = register(new Block("black_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f) + public static final Block BLACK_GLAZED_TERRACOTTA = register(new Block("black_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block WHITE_CONCRETE = register(new Block("white_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); public static final Block ORANGE_CONCRETE = register(new Block("orange_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); @@ -1692,11 +1692,11 @@ public final class Blocks { public static final Block GREEN_CONCRETE_POWDER = register(new Block("green_concrete_powder", builder().destroyTime(0.5f))); public static final Block RED_CONCRETE_POWDER = register(new Block("red_concrete_powder", builder().destroyTime(0.5f))); public static final Block BLACK_CONCRETE_POWDER = register(new Block("black_concrete_powder", builder().destroyTime(0.5f))); - public static final Block KELP = register(new Block("kelp", builder() + public static final Block KELP = register(new Block("kelp", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block KELP_PLANT = register(new Block("kelp_plant", builder())); + public static final Block KELP_PLANT = register(new Block("kelp_plant", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block DRIED_KELP_BLOCK = register(new Block("dried_kelp_block", builder().destroyTime(0.5f))); - public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder().destroyTime(0.5f) + public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .intState(EGGS, 1, 4) .intState(HATCH, 0, 2))); public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder().destroyTime(0.5f) @@ -1721,15 +1721,15 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block TUBE_CORAL = register(new Block("tube_coral", builder() + public static final Block TUBE_CORAL = register(new Block("tube_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder() + public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder() + public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block FIRE_CORAL = register(new Block("fire_coral", builder() + public static final Block FIRE_CORAL = register(new Block("fire_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block HORN_CORAL = register(new Block("horn_coral", builder() + public static final Block HORN_CORAL = register(new Block("horn_coral", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); @@ -1741,15 +1741,15 @@ public final class Blocks { .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder().requiresCorrectToolForDrops() .booleanState(WATERLOGGED))); - public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder() + public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder() + public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder() + public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder() + public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); - public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder() + public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); public static final Block DEAD_TUBE_CORAL_WALL_FAN = register(new Block("dead_tube_coral_wall_fan", builder().requiresCorrectToolForDrops() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -1766,36 +1766,36 @@ public final class Blocks { public static final Block DEAD_HORN_CORAL_WALL_FAN = register(new Block("dead_horn_coral_wall_fan", builder().requiresCorrectToolForDrops() .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block TUBE_CORAL_WALL_FAN = register(new Block("tube_coral_wall_fan", builder() + public static final Block TUBE_CORAL_WALL_FAN = register(new Block("tube_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block BRAIN_CORAL_WALL_FAN = register(new Block("brain_coral_wall_fan", builder() + public static final Block BRAIN_CORAL_WALL_FAN = register(new Block("brain_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block BUBBLE_CORAL_WALL_FAN = register(new Block("bubble_coral_wall_fan", builder() + public static final Block BUBBLE_CORAL_WALL_FAN = register(new Block("bubble_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block FIRE_CORAL_WALL_FAN = register(new Block("fire_coral_wall_fan", builder() + public static final Block FIRE_CORAL_WALL_FAN = register(new Block("fire_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block HORN_CORAL_WALL_FAN = register(new Block("horn_coral_wall_fan", builder() + public static final Block HORN_CORAL_WALL_FAN = register(new Block("horn_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder() + public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder().pushReaction(PistonBehavior.DESTROY) .intState(PICKLES, 1, 4) .booleanState(WATERLOGGED))); public static final Block BLUE_ICE = register(new Block("blue_ice", builder().destroyTime(2.8f))); public static final Block CONDUIT = register(new Block("conduit", builder().setBlockEntity().destroyTime(3.0f) .booleanState(WATERLOGGED))); - public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f))); - public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f) + public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); + public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) .intState(AGE_1, 0, 1) .enumState(BAMBOO_LEAVES, "none", "small", "large") .intState(STAGE, 0, 1))); - public static final Block POTTED_BAMBOO = register(new Block("potted_bamboo", builder())); + public static final Block POTTED_BAMBOO = register(new FlowerPotBlock("potted_bamboo", BAMBOO, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block VOID_AIR = register(new Block("void_air", builder())); public static final Block CAVE_AIR = register(new Block("cave_air", builder())); - public static final Block BUBBLE_COLUMN = register(new Block("bubble_column", builder() + public static final Block BUBBLE_COLUMN = register(new Block("bubble_column", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(DRAG))); public static final Block POLISHED_GRANITE_STAIRS = register(new Block("polished_granite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -1997,7 +1997,7 @@ public final class Blocks { .booleanState(UP) .booleanState(WATERLOGGED) .enumState(WEST_WALL, "none", "low", "tall"))); - public static final Block SCAFFOLDING = register(new Block("scaffolding", builder() + public static final Block SCAFFOLDING = register(new Block("scaffolding", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(BOTTOM) .intState(STABILITY_DISTANCE, 0, 7) .booleanState(WATERLOGGED))); @@ -2014,24 +2014,24 @@ public final class Blocks { .booleanState(LIT))); public static final Block CARTOGRAPHY_TABLE = register(new Block("cartography_table", builder().destroyTime(2.5f))); public static final Block FLETCHING_TABLE = register(new Block("fletching_table", builder().destroyTime(2.5f))); - public static final Block GRINDSTONE = register(new Block("grindstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f) + public static final Block GRINDSTONE = register(new Block("grindstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f).pushReaction(PistonBehavior.BLOCK) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block LECTERN = register(new Block("lectern", builder().setBlockEntity().destroyTime(2.5f) + public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity().destroyTime(2.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(HAS_BOOK) .booleanState(POWERED))); public static final Block SMITHING_TABLE = register(new Block("smithing_table", builder().destroyTime(2.5f))); public static final Block STONECUTTER = register(new Block("stonecutter", builder().requiresCorrectToolForDrops().destroyTime(3.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); - public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f) + public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) .enumState(BELL_ATTACHMENT, "floor", "ceiling", "single_wall", "double_wall") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block LANTERN = register(new Block("lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f) + public static final Block LANTERN = register(new Block("lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); - public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f) + public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(HANGING) .booleanState(WATERLOGGED))); public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity().destroyTime(2.0f) @@ -2044,7 +2044,7 @@ public final class Blocks { .booleanState(LIT) .booleanState(SIGNAL_FIRE) .booleanState(WATERLOGGED))); - public static final Block SWEET_BERRY_BUSH = register(new Block("sweet_berry_bush", builder() + public static final Block SWEET_BERRY_BUSH = register(new Block("sweet_berry_bush", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_3, 0, 3))); public static final Block WARPED_STEM = register(new Block("warped_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); @@ -2055,10 +2055,10 @@ public final class Blocks { public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); public static final Block WARPED_NYLIUM = register(new Block("warped_nylium", builder().requiresCorrectToolForDrops().destroyTime(0.4f))); - public static final Block WARPED_FUNGUS = register(new Block("warped_fungus", builder())); + public static final Block WARPED_FUNGUS = register(new Block("warped_fungus", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block WARPED_WART_BLOCK = register(new Block("warped_wart_block", builder().destroyTime(1.0f))); - public static final Block WARPED_ROOTS = register(new Block("warped_roots", builder())); - public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder())); + public static final Block WARPED_ROOTS = register(new Block("warped_roots", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block CRIMSON_STEM = register(new Block("crimson_stem", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder().destroyTime(2.0f) @@ -2068,15 +2068,15 @@ public final class Blocks { public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder().destroyTime(2.0f) .enumState(AXIS, Axis.VALUES))); public static final Block CRIMSON_NYLIUM = register(new Block("crimson_nylium", builder().requiresCorrectToolForDrops().destroyTime(0.4f))); - public static final Block CRIMSON_FUNGUS = register(new Block("crimson_fungus", builder())); + public static final Block CRIMSON_FUNGUS = register(new Block("crimson_fungus", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SHROOMLIGHT = register(new Block("shroomlight", builder().destroyTime(1.0f))); - public static final Block WEEPING_VINES = register(new Block("weeping_vines", builder() + public static final Block WEEPING_VINES = register(new Block("weeping_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder())); - public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder() + public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25))); - public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder())); - public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder())); + public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block CRIMSON_PLANKS = register(new Block("crimson_planks", builder().destroyTime(2.0f))); public static final Block WARPED_PLANKS = register(new Block("warped_planks", builder().destroyTime(2.0f))); public static final Block CRIMSON_SLAB = register(new Block("crimson_slab", builder().destroyTime(2.0f) @@ -2085,9 +2085,9 @@ public final class Blocks { public static final Block WARPED_SLAB = register(new Block("warped_slab", builder().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f) + public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f) + public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); public static final Block CRIMSON_FENCE = register(new Block("crimson_fence", builder().destroyTime(2.0f) .booleanState(EAST) @@ -2133,21 +2133,21 @@ public final class Blocks { .enumState(HALF, "top", "bottom") .enumState(STAIRS_SHAPE, "straight", "inner_left", "inner_right", "outer_left", "outer_right") .booleanState(WATERLOGGED))); - public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f) + public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f) + public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); - public static final Block CRIMSON_DOOR = register(new Block("crimson_door", builder().destroyTime(3.0f) + public static final Block CRIMSON_DOOR = register(new DoorBlock("crimson_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WARPED_DOOR = register(new Block("warped_door", builder().destroyTime(3.0f) + public static final Block WARPED_DOOR = register(new DoorBlock("warped_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -2186,11 +2186,11 @@ public final class Blocks { public static final Block CRYING_OBSIDIAN = register(new Block("crying_obsidian", builder().requiresCorrectToolForDrops().destroyTime(50.0f))); public static final Block RESPAWN_ANCHOR = register(new Block("respawn_anchor", builder().requiresCorrectToolForDrops().destroyTime(50.0f) .intState(RESPAWN_ANCHOR_CHARGES, 0, 4))); - public static final Block POTTED_CRIMSON_FUNGUS = register(new Block("potted_crimson_fungus", builder())); - public static final Block POTTED_WARPED_FUNGUS = register(new Block("potted_warped_fungus", builder())); - public static final Block POTTED_CRIMSON_ROOTS = register(new Block("potted_crimson_roots", builder())); - public static final Block POTTED_WARPED_ROOTS = register(new Block("potted_warped_roots", builder())); - public static final Block LODESTONE = register(new Block("lodestone", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); + public static final Block POTTED_CRIMSON_FUNGUS = register(new FlowerPotBlock("potted_crimson_fungus", CRIMSON_FUNGUS, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WARPED_FUNGUS = register(new FlowerPotBlock("potted_warped_fungus", WARPED_FUNGUS, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_CRIMSON_ROOTS = register(new FlowerPotBlock("potted_crimson_roots", CRIMSON_ROOTS, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_WARPED_ROOTS = register(new FlowerPotBlock("potted_warped_roots", WARPED_ROOTS, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block LODESTONE = register(new Block("lodestone", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.BLOCK))); public static final Block BLACKSTONE = register(new Block("blackstone", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block BLACKSTONE_STAIRS = register(new Block("blackstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) @@ -2235,9 +2235,9 @@ public final class Blocks { public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f) + public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(POWERED))); - public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f) + public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .enumState(ATTACH_FACE, "floor", "wall", "ceiling") .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(POWERED))); @@ -2251,120 +2251,120 @@ public final class Blocks { public static final Block CHISELED_NETHER_BRICKS = register(new Block("chiseled_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block CRACKED_NETHER_BRICKS = register(new Block("cracked_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block QUARTZ_BRICKS = register(new Block("quartz_bricks", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); - public static final Block CANDLE = register(new Block("candle", builder().destroyTime(0.1f) + public static final Block CANDLE = register(new Block("candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f) + public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f) + public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f) + public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f) + public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f) + public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f) + public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f) + public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f) + public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f) + public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f) + public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f) + public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f) + public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f) + public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f) + public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f) + public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f) + public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .intState(CANDLES, 1, 4) .booleanState(LIT) .booleanState(WATERLOGGED))); - public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f) + public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f) + public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f) + public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f) + public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f) + public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f) + public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f) + public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f) + public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f) + public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f) + public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f) + public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f) + public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f) + public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f) + public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f) + public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f) + public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); - public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f) + public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) .booleanState(LIT))); public static final Block AMETHYST_BLOCK = register(new Block("amethyst_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); - public static final Block BUDDING_AMETHYST = register(new Block("budding_amethyst", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); - public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder().destroyTime(1.5f) + public static final Block BUDDING_AMETHYST = register(new Block("budding_amethyst", builder().requiresCorrectToolForDrops().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY))); + public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); - public static final Block LARGE_AMETHYST_BUD = register(new Block("large_amethyst_bud", builder().destroyTime(1.5f) + public static final Block LARGE_AMETHYST_BUD = register(new Block("large_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); - public static final Block MEDIUM_AMETHYST_BUD = register(new Block("medium_amethyst_bud", builder().destroyTime(1.5f) + public static final Block MEDIUM_AMETHYST_BUD = register(new Block("medium_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); - public static final Block SMALL_AMETHYST_BUD = register(new Block("small_amethyst_bud", builder().destroyTime(1.5f) + public static final Block SMALL_AMETHYST_BUD = register(new Block("small_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); public static final Block TUFF = register(new Block("tuff", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); @@ -2430,7 +2430,7 @@ public final class Blocks { .enumState(SCULK_SENSOR_PHASE, "inactive", "active", "cooldown") .booleanState(WATERLOGGED))); public static final Block SCULK = register(new Block("sculk", builder().destroyTime(0.2f))); - public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder().destroyTime(0.2f) + public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) .booleanState(DOWN) .booleanState(EAST) .booleanState(NORTH) @@ -2534,49 +2534,49 @@ public final class Blocks { public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) .enumState(SLAB_TYPE, "top", "bottom", "double") .booleanState(WATERLOGGED))); - public static final Block COPPER_DOOR = register(new Block("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block COPPER_DOOR = register(new DoorBlock("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block EXPOSED_COPPER_DOOR = register(new Block("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block EXPOSED_COPPER_DOOR = register(new DoorBlock("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block OXIDIZED_COPPER_DOOR = register(new Block("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block OXIDIZED_COPPER_DOOR = register(new DoorBlock("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WEATHERED_COPPER_DOOR = register(new Block("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block WEATHERED_COPPER_DOOR = register(new DoorBlock("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_COPPER_DOOR = register(new Block("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block WAXED_COPPER_DOOR = register(new DoorBlock("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new Block("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new DoorBlock("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new Block("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new DoorBlock("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") .booleanState(OPEN) .booleanState(POWERED))); - public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new Block("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f) + public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new DoorBlock("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .enumState(DOOR_HINGE, "left", "right") @@ -2674,36 +2674,36 @@ public final class Blocks { .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) .booleanState(POWERED) .booleanState(WATERLOGGED))); - public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder().destroyTime(1.5f) + public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) .enumState(DRIPSTONE_THICKNESS, "tip_merge", "tip", "frustum", "middle", "base") .enumState(VERTICAL_DIRECTION, Direction.UP, Direction.DOWN) .booleanState(WATERLOGGED))); public static final Block DRIPSTONE_BLOCK = register(new Block("dripstone_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); - public static final Block CAVE_VINES = register(new Block("cave_vines", builder() + public static final Block CAVE_VINES = register(new Block("cave_vines", builder().pushReaction(PistonBehavior.DESTROY) .intState(AGE_25, 0, 25) .booleanState(BERRIES))); - public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder() + public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(BERRIES))); - public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder())); - public static final Block AZALEA = register(new Block("azalea", builder())); - public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder())); - public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder().destroyTime(0.1f))); - public static final Block PINK_PETALS = register(new Block("pink_petals", builder() + public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block AZALEA = register(new Block("azalea", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY))); + public static final Block PINK_PETALS = register(new Block("pink_petals", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .intState(FLOWER_AMOUNT, 1, 4))); - public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f))); - public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f) + public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY))); + public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(TILT, "none", "unstable", "partial", "full") .booleanState(WATERLOGGED))); - public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder().destroyTime(0.1f) + public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); - public static final Block SMALL_DRIPLEAF = register(new Block("small_dripleaf", builder() + public static final Block SMALL_DRIPLEAF = register(new Block("small_dripleaf", builder().pushReaction(PistonBehavior.DESTROY) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .enumState(DOUBLE_BLOCK_HALF, "upper", "lower") .booleanState(WATERLOGGED))); - public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder() + public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder().pushReaction(PistonBehavior.DESTROY) .booleanState(WATERLOGGED))); public static final Block ROOTED_DIRT = register(new Block("rooted_dirt", builder().destroyTime(0.5f))); public static final Block MUD = register(new Block("mud", builder().destroyTime(0.5f))); @@ -2782,17 +2782,17 @@ public final class Blocks { public static final Block RAW_IRON_BLOCK = register(new Block("raw_iron_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block RAW_COPPER_BLOCK = register(new Block("raw_copper_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block RAW_GOLD_BLOCK = register(new Block("raw_gold_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); - public static final Block POTTED_AZALEA_BUSH = register(new Block("potted_azalea_bush", builder())); - public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new Block("potted_flowering_azalea_bush", builder())); + public static final Block POTTED_AZALEA_BUSH = register(new FlowerPotBlock("potted_azalea_bush", AZALEA, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new FlowerPotBlock("potted_flowering_azalea_bush", FLOWERING_AZALEA, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block OCHRE_FROGLIGHT = register(new Block("ochre_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder().destroyTime(0.3f) .enumState(AXIS, Axis.VALUES))); - public static final Block FROGSPAWN = register(new Block("frogspawn", builder())); + public static final Block FROGSPAWN = register(new Block("frogspawn", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block REINFORCED_DEEPSLATE = register(new Block("reinforced_deepslate", builder().destroyTime(55.0f))); - public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity() + public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY) .booleanState(CRACKED) .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) .booleanState(WATERLOGGED))); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java index bbb6f8fe3..339d82f96 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java @@ -118,7 +118,7 @@ public final class Properties { public static final Property RESPAWN_ANCHOR_CHARGES = Property.create("charges"); public static final Property ROTATION_16 = Property.create("rotation"); public static final Property BED_PART = Property.create("part"); - public static final Property CHEST_TYPE = Property.create("type"); + public static final Property CHEST_TYPE = Property.create("type"); public static final Property MODE_COMPARATOR = Property.create("mode"); public static final Property DOOR_HINGE = Property.create("hinge"); public static final Property NOTEBLOCK_INSTRUMENT = Property.create("instrument"); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java index 84822ca16..3114f31f9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/Block.java @@ -30,8 +30,15 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.property.Property; +import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.Identifier; import java.util.*; @@ -44,6 +51,7 @@ public class Block { private final boolean requiresCorrectToolForDrops; private final boolean hasBlockEntity; private final float destroyTime; + private final @NonNull PistonBehavior pushReaction; private int javaId = -1; public Block(String javaIdentifier, Builder builder) { @@ -51,9 +59,76 @@ public class Block { this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops; this.hasBlockEntity = builder.hasBlockEntity; this.destroyTime = builder.destroyTime; + this.pushReaction = builder.pushReaction; builder.build(this); } + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + BlockDefinition definition = session.getBlockMappings().getBedrockBlock(state); + sendBlockUpdatePacket(session, state, definition, position); + + { + // Extended collision boxes for custom blocks + if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { + int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); + BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(state.javaId()); + int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); + BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); + if (belowBedrockExtendedCollisionDefinition != null && state.is(Blocks.AIR)) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position); + updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } else if (aboveBlock == Block.JAVA_AIR_ID) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + } + } + } + + handleLecternBlockUpdate(session, state, position); + } + + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); + updateBlockPacket.setDataLayer(0); + updateBlockPacket.setBlockPosition(position); + updateBlockPacket.setDefinition(definition); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + session.sendUpstreamPacket(updateBlockPacket); + + UpdateBlockPacket waterPacket = new UpdateBlockPacket(); + waterPacket.setDataLayer(1); + waterPacket.setBlockPosition(position); + if (BlockRegistries.WATERLOGGED.get().get(state.javaId())) { + waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); + } else { + waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + } + session.sendUpstreamPacket(waterPacket); + } + + protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { + // Block state is out of bounds of this map - lectern has been destroyed, if it existed + if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled(session)) { + session.getLecternCache().remove(position); + } + } + public String javaIdentifier() { return javaIdentifier; } @@ -70,6 +145,11 @@ public class Block { return destroyTime; } + @NonNull + public PistonBehavior pushReaction() { + return this.pushReaction; + } + public int javaId() { return javaId; } @@ -97,6 +177,7 @@ public class Block { private final Map, List>> states = new LinkedHashMap<>(); private boolean requiresCorrectToolForDrops = false; private boolean hasBlockEntity = false; + private PistonBehavior pushReaction = PistonBehavior.NORMAL; private float destroyTime; /** @@ -143,6 +224,11 @@ public class Block { return this; } + public Builder pushReaction(PistonBehavior pushReaction) { + this.pushReaction = pushReaction; + return this; + } + private void build(Block block) { if (states.isEmpty()) { BlockRegistries.BLOCK_STATES.get().add(new BlockState(block, BlockRegistries.BLOCK_STATES.get().size())); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java index 936b711e4..23e89d99f 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/BlockState.java @@ -58,6 +58,10 @@ public final class BlockState { return javaId; } + public boolean is(Block block) { + return this.block == block; + } + public static BlockState of(int javaId) { return BlockRegistries.BLOCK_STATES.get(javaId); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java new file mode 100644 index 000000000..d27969af7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/CauldronBlock.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtList; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtType; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; + +public class CauldronBlock extends Block implements BedrockChunkWantsBlockEntityTag { + public CauldronBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) + return BlockEntityTranslator.getConstantBedrockTag("Cauldron", position.getX(), position.getY(), position.getZ()) + .putByte("isMovable", (byte) 0) + .putShort("PotionId", (short) -1) + .putShort("PotionType", (short) -1) + .putList("Items", NbtType.END, NbtList.EMPTY) + .build(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java new file mode 100644 index 000000000..69132ccfd --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/ChestBlock.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.property.ChestType; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.util.BlockEntityUtils; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; + +public class ChestBlock extends Block { + public ChestBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); + + if (state.getValue(Properties.CHEST_TYPE) != ChestType.SINGLE) { + NbtMapBuilder tagBuilder = BlockEntityTranslator.getConstantBedrockTag(BlockEntityType.CHEST, position.getX(), position.getY(), position.getZ()); + BlockEntityUtils.getBlockEntityTranslator(BlockEntityType.CHEST).translateTag(session, tagBuilder, null, state); //TODO + BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java new file mode 100644 index 000000000..bfde51a79 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/DoorBlock.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.ChunkUtils; + +public class DoorBlock extends Block { + public DoorBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); + + if (state.getValue(Properties.DOUBLE_BLOCK_HALF).equals("upper")) { + // 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); + BlockState belowDoorBlockState = session.getGeyser().getWorldManager().blockAt(session, belowDoorPosition.getX(), belowDoorPosition.getY(), belowDoorPosition.getZ()); + ChunkUtils.updateBlock(session, belowDoorBlockState, belowDoorPosition); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java similarity index 60% rename from core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java index 0a60b0f32..8c911ad97 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/FlowerPotBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 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 @@ -23,65 +23,35 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.level.block.entity; +package org.geysermc.geyser.level.block.type; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.util.BlockEntityUtils; -public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { - /** - * @param blockState the Java block state of a potential flower pot block - * @return true if the block is a flower pot - */ - public static boolean isFlowerBlock(int blockState) { - return BlockStateValues.getFlowerPotValues().containsKey(blockState); - } +public class FlowerPotBlock extends Block implements BedrockChunkWantsBlockEntityTag { + private final Block flower; - /** - * Get the Nukkit CompoundTag of the flower pot. - * - * @param blockState Java block state of flower pot. - * @param position Bedrock position of flower pot. - * @return Bedrock tag of flower pot. - */ - public static NbtMap getTag(GeyserSession session, int blockState, Vector3i position) { - NbtMapBuilder tagBuilder = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putByte("isMovable", (byte) 1) - .putString("id", "FlowerPot"); - // Get the Java name of the plant inside. e.g. minecraft:oak_sapling - String name = BlockStateValues.getFlowerPotValues().get(blockState); - if (name != null) { - // Get the Bedrock CompoundTag of the block. - // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(name); - if (plant != null) { - tagBuilder.put("PlantBlock", plant.toBuilder().build()); - } - } - return tagBuilder.build(); + public FlowerPotBlock(String javaIdentifier, Block flower, Builder builder) { + super(javaIdentifier, builder); + this.flower = flower; } @Override - public boolean isBlock(int blockState) { - return isFlowerBlock(blockState); - } + public void updateBlock(GeyserSession session, BlockState state, Vector3i position) { + super.updateBlock(session, state, position); - @Override - public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { - NbtMap tag = getTag(session, blockState.javaId(), position); + NbtMap tag = createTag(session, position, state); BlockEntityUtils.updateBlockEntity(session, tag, position); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(blockState.javaId())); + updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockBlock(state)); updateBlockPacket.setBlockPosition(position); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); @@ -89,4 +59,20 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity { session.sendUpstreamPacket(updateBlockPacket); BlockEntityUtils.updateBlockEntity(session, tag, position); } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + NbtMapBuilder tagBuilder = BlockEntityTranslator.getConstantBedrockTag("FlowerPot", position.getX(), position.getY(), position.getZ()) + .putByte("isMovable", (byte) 1); + // Get the Java name of the plant inside. e.g. minecraft:oak_sapling + if (this.flower != Blocks.AIR) { + // Get the Bedrock CompoundTag of the block. + // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. + NbtMap plant = session.getBlockMappings().getFlowerPotBlocks().get(this.flower.javaIdentifier()); + if (plant != null) { + tagBuilder.putCompound("PlantBlock", plant.toBuilder().build()); + } + } + return tagBuilder.build(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java new file mode 100644 index 000000000..6b8aa02b5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/LecternBlock.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.erosion.util.LecternUtils; +import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.BlockEntityUtils; + +public class LecternBlock extends Block { + public LecternBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void handleLecternBlockUpdate(GeyserSession session, BlockState state, Vector3i position) { + WorldManager worldManager = session.getGeyser().getWorldManager(); + if (worldManager.shouldExpectLecternHandled(session)) { + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); + return; + } + + boolean currentHasBook = state.getValue(Properties.HAS_BOOK); + Boolean previousHasBook = worldManager.blockAt(session, position).getValue(Properties.HAS_BOOK); // Can be null if not a lectern, watch out + if (currentHasBook != previousHasBook) { + if (currentHasBook) { + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); + } else { + session.getLecternCache().remove(position); + NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); + BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java new file mode 100644 index 000000000..e4df8d88b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/MovingPistonBlock.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.geysermc.geyser.session.GeyserSession; + +public class MovingPistonBlock extends Block { + public MovingPistonBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + // Prevent moving_piston from being placed + // It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java new file mode 100644 index 000000000..fc54115eb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/PistonBlock.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; +import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; + +public class PistonBlock extends Block implements BedrockChunkWantsBlockEntityTag { + public PistonBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + public NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState) { + boolean extended = blockState.getValue(Properties.EXTENDED); + boolean sticky = blockState.is(Blocks.STICKY_PISTON); + return PistonBlockEntity.buildStaticPistonTag(position, extended, sticky); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java new file mode 100644 index 000000000..01a757eae --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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.level.block.type; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.SkullCache; + +public class SkullBlock extends Block { + public SkullBlock(String javaIdentifier, Builder builder) { + super(javaIdentifier, builder); + } + + @Override + protected void sendBlockUpdatePacket(GeyserSession session, BlockState state, BlockDefinition definition, Vector3i position) { + int skullVariant = BlockStateValues.getSkullVariant(state.javaId()); // TODO + if (skullVariant == -1) { + // Skull is gone + session.getSkullCache().removeSkull(position); + } else if (skullVariant == 3) { + // The changed block was a player skull so check if a custom block was defined for this skull + SkullCache.Skull skull = session.getSkullCache().updateSkull(position, state.javaId()); + if (skull != null && skull.getBlockDefinition() != null) { + definition = skull.getBlockDefinition(); + } + } + super.sendBlockUpdatePacket(session, state, definition, position); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 64b466f12..66301cef2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -424,39 +424,12 @@ public final class BlockRegistryPopulator { // TODO fix this, (no block should have a null hardness) BlockMapping.BlockMappingBuilder builder = BlockMapping.builder(); - JsonNode hardnessNode = entry.getValue().get("block_hardness"); - if (hardnessNode != null) { - builder.hardness(hardnessNode.floatValue()); - } - - JsonNode canBreakWithHandNode = entry.getValue().get("can_break_with_hand"); - if (canBreakWithHandNode != null) { - builder.canBreakWithHand(canBreakWithHandNode.booleanValue()); - } else { - builder.canBreakWithHand(false); - } - - JsonNode collisionIndexNode = entry.getValue().get("collision_index"); - if (hardnessNode != null) { - builder.collisionIndex(collisionIndexNode.intValue()); - } JsonNode pickItemNode = entry.getValue().get("pick_item"); if (pickItemNode != null) { builder.pickItem(pickItemNode.textValue().intern()); } - if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor") || javaId.startsWith("minecraft:reinforced_deepslate")) { - builder.pistonBehavior(PistonBehavior.BLOCK); - } else { - JsonNode pistonBehaviorNode = entry.getValue().get("piston_behavior"); - if (pistonBehaviorNode != null) { - builder.pistonBehavior(PistonBehavior.getByName(pistonBehaviorNode.textValue())); - } else { - builder.pistonBehavior(PistonBehavior.NORMAL); - } - } - JsonNode hasBlockEntityNode = entry.getValue().get("has_block_entity"); if (hasBlockEntityNode != null) { builder.isBlockEntity(hasBlockEntityNode.booleanValue()); @@ -475,7 +448,6 @@ public final class BlockRegistryPopulator { } builder.javaIdentifier(javaId); - builder.javaBlockId(uniqueJavaId); BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, javaRuntimeId); BlockRegistries.JAVA_BLOCKS.register(javaRuntimeId, builder.build()); @@ -547,26 +519,23 @@ public final class BlockRegistryPopulator { int stateRuntimeId = javaBlockState.javaId(); String pistonBehavior = javaBlockState.pistonBehavior(); BlockMapping blockMapping = BlockMapping.builder() - .canBreakWithHand(javaBlockState.canBreakWithHand()) .pickItem(javaBlockState.pickItem()) .isNonVanilla(true) .javaIdentifier(javaId) - .javaBlockId(javaBlockState.stateGroupId()) - .hardness(javaBlockState.blockHardness()) - .pistonBehavior(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)) - .isBlockEntity(javaBlockState.hasBlockEntity()) .build(); Block.Builder builder = Block.builder() - .destroyTime(javaBlockState.blockHardness()); + .destroyTime(javaBlockState.blockHardness()) + .pushReaction(pistonBehavior == null ? PistonBehavior.NORMAL : PistonBehavior.getByName(pistonBehavior)); if (!javaBlockState.canBreakWithHand()) { builder.requiresCorrectToolForDrops(); } if (javaBlockState.hasBlockEntity()) { builder.setBlockEntity(); } - String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier()); + Block block = new Block(cleanJavaIdentifier, builder); + String bedrockIdentifier = customBlockState.block().identifier(); if (!cleanJavaIdentifier.equals(cleanIdentifiers.peekLast())) { @@ -574,6 +543,7 @@ public final class BlockRegistryPopulator { cleanIdentifiers.add(cleanJavaIdentifier.intern()); } + BlockRegistries.JAVA_BLOCKS_TO_RENAME.get().add(javaBlockState.stateGroupId(), block); //TODO don't allow duplicates, allow blanks BlockRegistries.JAVA_IDENTIFIER_TO_ID.register(javaId, stateRuntimeId); BlockRegistries.JAVA_BLOCKS.register(stateRuntimeId, blockMapping); diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java index 0196ac22f..d6ee55965 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java @@ -27,32 +27,19 @@ package org.geysermc.geyser.registry.type; import lombok.Builder; import lombok.Value; -import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.util.BlockUtils; @Builder @Value public class BlockMapping { - public static BlockMapping DEFAULT = BlockMapping.builder().javaIdentifier("minecraft:air").pistonBehavior(PistonBehavior.NORMAL).build(); + public static BlockMapping DEFAULT = BlockMapping.builder().javaIdentifier("minecraft:air").build(); String javaIdentifier; - /** - * The block ID shared between all different block states of this block. - * NOT the runtime ID! - */ - int javaBlockId; - float hardness; boolean canBreakWithHand; - /** - * The index of this collision in collision.json - */ - int collisionIndex; @Nullable String pickItem; - @NonNull PistonBehavior pistonBehavior; boolean isBlockEntity; boolean isNonVanilla; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index c76f024af..2fe808070 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.level.block.type.BlockState; import java.util.List; import java.util.Map; @@ -78,6 +79,10 @@ public class BlockMappings implements DefinitionRegistry { return this.javaToBedrockBlocks[javaState]; } + public GeyserBedrockBlock getBedrockBlock(BlockState javaState) { + return this.getBedrockBlock(javaState.javaId()); + } + public GeyserBedrockBlock getVanillaBedrockBlock(int javaState) { if (javaState < 0 || javaState >= this.javaToVanillaBedrockBlocks.length) { return bedrockAir; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index 6da354646..95f5c1cc3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -30,7 +30,6 @@ import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.BlockTag; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -107,17 +106,6 @@ public final class TagCache { return false; } - /** - * @return true if the block tag is present and contains this block mapping's Java ID. - */ - public boolean is(BlockTag tag, BlockMapping mapping) { - IntList values = this.blocks.get(tag); - if (values != null) { - return values.contains(mapping.getJavaBlockId()); - } - return false; - } - /** * @return true if the item tag is present and contains this item stack's Java ID. */ diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index c84126608..44ec7a6b9 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -180,7 +180,7 @@ public final class WorldCache { // This block may be out of sync with the server // In 1.19.0 Java, you can verify this by trying to mine in spawn protection Vector3i position = entry.getKey(); - ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().getBlockAt(session, position), position); + ChunkUtils.updateBlockClientSide(session, session.getGeyser().getWorldManager().blockAt(session, position), position); it.remove(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java similarity index 59% rename from core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java index a55fa8a62..189fb2c65 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockChunkWantsBlockEntityTag.java @@ -27,32 +27,18 @@ package org.geysermc.geyser.translator.level.block.entity; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.session.GeyserSession; /** - * Pistons are a special case where they are only a block entity on Bedrock. + * Implemented only if a block is a block entity in Bedrock and not Java Edition. */ -public class PistonBlockEntityTranslator { +public interface BedrockChunkWantsBlockEntityTag extends RequiresBlockState { /** - * Used in ChunkUtils to determine if the block is a piston. - * + * Get the tag of the Bedrock-only block entity. Used during chunk loading. + * @param position Bedrock position of block. * @param blockState Java BlockState of block. - * @return if block is a piston or not. + * @return Bedrock tag */ - public static boolean isBlock(int blockState) { - return BlockStateValues.getPistonValues().containsKey(blockState); - } - - /** - * Calculates the Nukkit CompoundTag to send to the client on chunk - * - * @param blockState Java block state of block. - * @param position Bedrock position of piston. - * @return Bedrock tag of piston. - */ - public static NbtMap getTag(int blockState, Vector3i position) { - boolean extended = BlockStateValues.getPistonValues().get(blockState); - boolean sticky = BlockStateValues.isStickyPiston(blockState); - return PistonBlockEntity.buildStaticPistonTag(position, extended, sticky); - } + NbtMap createTag(GeyserSession session, Vector3i position, BlockState blockState); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java deleted file mode 100644 index 01e2d3e74..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019-2022 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.translator.level.block.entity; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtList; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtType; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.session.GeyserSession; - -/** - * Implemented only if a block is a block entity in Bedrock and not Java Edition. - */ -public interface BedrockOnlyBlockEntity extends RequiresBlockState { - /** - * Determines if block is part of class - * @param blockState BlockState to be compared - * @return true if part of the class - */ - boolean isBlock(int blockState); - - /** - * Update the block on Bedrock Edition. - * @param session GeyserConnection. - * @param blockState The Java block state. - * @param position The Bedrock block position. - */ - void updateBlock(GeyserSession session, BlockState blockState, Vector3i position); - - /** - * Get the tag of the Bedrock-only block entity - * @param position Bedrock position of block. - * @param blockState Java BlockState of block. - * @return Bedrock tag, or null if not a Bedrock-only Block Entity - */ - static @Nullable NbtMap getTag(GeyserSession session, Vector3i position, int blockState) { - if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) { - return FlowerPotBlockEntityTranslator.getTag(session, blockState, position); - } else if (PistonBlockEntityTranslator.isBlock(blockState)) { - return PistonBlockEntityTranslator.getTag(blockState, position); - } else if (BlockStateValues.isCauldron(blockState)) { - // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) - return NbtMap.builder() - .putString("id", "Cauldron") - .putByte("isMovable", (byte) 0) - .putShort("PotionId", (short) -1) - .putShort("PotionType", (short) -1) - .putList("Items", NbtType.END, NbtList.EMPTY) - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .build(); - } - return null; - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index 63c5f71f3..102f4a0e6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -25,33 +25,20 @@ package org.geysermc.geyser.translator.level.block.entity; -import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.ChestType; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; /** - * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity + * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockChunkWantsBlockEntityTag */ @BlockEntity(type = { BlockEntityType.CHEST, BlockEntityType.TRAPPED_CHEST }) -public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity { - @Override - public boolean isBlock(int blockState) { - return BlockStateValues.getDoubleChestValues().containsKey(blockState); - } - - @Override - public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(BlockEntityType.CHEST), position.getX(), position.getY(), position.getZ()); - translateTag(session, tagBuilder, null, blockState); - BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); - } +public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap javaNbt, BlockState blockState) { @@ -71,7 +58,7 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl public static void translateChestValue(NbtMapBuilder builder, BlockState state, int x, int z) { // Calculate the position of the other chest based on the Java block state Direction facing = state.getValue(Properties.HORIZONTAL_FACING); - boolean isLeft = state.getValue(Properties.CHEST_TYPE).equals("left"); //TODO enum + boolean isLeft = state.getValue(Properties.CHEST_TYPE) == ChestType.LEFT; switch (facing) { case EAST -> z = z + (isLeft ? 1 : -1); case WEST -> z = z + (isLeft ? -1 : 1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index e09f6ae42..abe3a197e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -25,7 +25,11 @@ package org.geysermc.geyser.translator.level.block.entity; +import it.unimi.dsi.fastutil.objects.*; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.level.block.type.PistonBlock; import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; @@ -33,9 +37,6 @@ import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; @@ -69,7 +70,7 @@ public class PistonBlockEntity { /** * A map of attached block positions to Java ids. */ - private final Object2IntMap attachedBlocks = new Object2IntOpenHashMap<>(); + private final Object2ObjectMap attachedBlocks = new Object2ObjectOpenHashMap<>(); /** * A flattened array of the positions of attached blocks, stored in XYZ order. */ @@ -158,7 +159,7 @@ public class PistonBlockEntity { BlockEntityUtils.updateBlockEntity(session, buildPistonTag(), position); } - public void setAction(PistonValueType action, Object2IntMap attachedBlocks) { + public void setAction(PistonValueType action, Map attachedBlocks) { // Don't check if this.action == action, since on some Paper versions BlockPistonRetractEvent is called multiple times // with the first 1-2 events being empty. placeFinalBlocks(); @@ -255,13 +256,13 @@ public class PistonBlockEntity { if (!blocksChecked.add(blockPos)) { continue; } - int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockPos); - if (blockId == Block.JAVA_AIR_ID) { + BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockPos); + if (state.block() == Blocks.AIR) { continue; } - if (BlockStateValues.canPistonMoveBlock(blockId, action == PistonValueType.PUSHING)) { - attachedBlocks.put(blockPos, blockId); - if (BlockStateValues.isBlockSticky(blockId)) { + if (BlockStateValues.canPistonMoveBlock(state, action == PistonValueType.PUSHING)) { + attachedBlocks.put(blockPos, state); + if (BlockStateValues.isBlockSticky(state)) { // For honey blocks and slime blocks check the blocks adjacent to it for (Direction direction : Direction.VALUES) { Vector3i offset = direction.getUnitVector(); @@ -278,13 +279,13 @@ public class PistonBlockEntity { if (action == PistonValueType.PULLING && position.add(directionOffset).equals(adjacentPos)) { continue; } - int adjacentBlockId = session.getGeyser().getWorldManager().getBlockAt(session, adjacentPos); - if (adjacentBlockId != Block.JAVA_AIR_ID && BlockStateValues.isBlockAttached(blockId, adjacentBlockId) && BlockStateValues.canPistonMoveBlock(adjacentBlockId, false)) { + BlockState adjacentBlockState = session.getGeyser().getWorldManager().blockAt(session, adjacentPos); + if (adjacentBlockState.block() != Blocks.AIR && BlockStateValues.isBlockAttached(state, adjacentBlockState) && BlockStateValues.canPistonMoveBlock(adjacentBlockState, false)) { // If it is another slime/honey block we need to check its adjacent blocks - if (BlockStateValues.isBlockSticky(adjacentBlockId)) { + if (BlockStateValues.isBlockSticky(adjacentBlockState)) { blocksToCheck.add(adjacentPos); } else { - attachedBlocks.put(adjacentPos, adjacentBlockId); + attachedBlocks.put(adjacentPos, adjacentBlockState); blocksChecked.add(adjacentPos); blocksToCheck.add(adjacentPos.add(movement)); } @@ -293,7 +294,7 @@ public class PistonBlockEntity { } // Check next block in line blocksToCheck.add(blockPos.add(movement)); - } else if (!BlockStateValues.canPistonDestroyBlock(blockId)) { + } else if (!BlockStateValues.canPistonDestroyBlock(state)) { // Block can't be moved or destroyed, so it blocks all block movement moveBlocks = false; break; @@ -350,24 +351,24 @@ public class PistonBlockEntity { playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() - shrink.getZ()); // Resolve collision with the piston head - int pistonHeadId = BlockStateValues.getPistonHead(orientation); + BlockState pistonHeadId = BlockState.of(BlockStateValues.getPistonHead(orientation)); pushPlayerBlock(pistonHeadId, getPistonHeadPos().toDouble(), blockMovement, playerBoundingBox); // Resolve collision with any attached moving blocks, but skip slime blocks // This prevents players from being launched by slime blocks covered by other blocks - for (Object2IntMap.Entry entry : attachedBlocks.object2IntEntrySet()) { - int blockId = entry.getIntValue(); - if (blockId != BlockStateValues.JAVA_SLIME_BLOCK_ID) { + for (Map.Entry entry : Object2ObjectMaps.fastIterable(attachedBlocks)) { + BlockState state = entry.getValue(); + if (!state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(blockId, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); } } // Resolve collision with slime blocks - for (Object2IntMap.Entry entry : attachedBlocks.object2IntEntrySet()) { - int blockId = entry.getIntValue(); - if (blockId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + for (Map.Entry entry : Object2ObjectMaps.fastIterable(attachedBlocks)) { + BlockState state = entry.getValue(); + if (state.is(Blocks.SLIME_BLOCK)) { Vector3d blockPos = entry.getKey().toDouble(); - pushPlayerBlock(blockId, blockPos, blockMovement, playerBoundingBox); + pushPlayerBlock(state, blockPos, blockMovement, playerBoundingBox); } } @@ -463,7 +464,7 @@ public class PistonBlockEntity { return maxIntersection; } - private void pushPlayerBlock(int javaId, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { + private void pushPlayerBlock(BlockState state, Vector3d startingPos, double blockMovement, BoundingBox playerBoundingBox) { PistonCache pistonCache = session.getPistonCache(); Vector3d movement = getMovement().toDouble(); // Check if the player collides with the movingBlock block entity @@ -471,14 +472,14 @@ public class PistonBlockEntity { if (SOLID_BOUNDING_BOX.checkIntersection(finalBlockPos, playerBoundingBox)) { pistonCache.setPlayerCollided(true); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); applySlimeBlockMotion(finalBlockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); } } Vector3d blockPos = startingPos.add(movement.mul(blockMovement)); - if (javaId == BlockStateValues.JAVA_HONEY_BLOCK_ID && isPlayerAttached(blockPos, playerBoundingBox)) { + if (state.is(Blocks.HONEY_BLOCK) && isPlayerAttached(blockPos, playerBoundingBox)) { pistonCache.setPlayerCollided(true); pistonCache.setPlayerAttachedToHoney(true); @@ -486,7 +487,7 @@ public class PistonBlockEntity { pistonCache.displacePlayer(movement.mul(delta)); } else { // Move the player out of collision - BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(javaId); + BlockCollision blockCollision = BlockRegistries.COLLISIONS.get(state.javaId()); if (blockCollision != null) { Vector3d extend = movement.mul(Math.min(1 - blockMovement, 0.5)); Direction movementDirection = orientation; @@ -499,7 +500,7 @@ public class PistonBlockEntity { pistonCache.setPlayerCollided(true); pistonCache.displacePlayer(movement.mul(intersection + 0.01d)); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { pistonCache.setPlayerSlimeCollision(true); applySlimeBlockMotion(blockPos, Vector3d.from(playerBoundingBox.getMiddleX(), playerBoundingBox.getMiddleY(), playerBoundingBox.getMiddleZ())); } @@ -509,7 +510,7 @@ public class PistonBlockEntity { } private BlockCollision getCollision(Vector3i blockPos) { - return BlockUtils.getCollision(getAttachedBlockId(blockPos)); + return BlockUtils.getCollision(getAttachedBlockId(blockPos).javaId()); } /** @@ -533,7 +534,7 @@ public class PistonBlockEntity { double y = blockPos.getY() + movementVec.getY() * movementProgress; double z = blockPos.getZ() + movementVec.getZ() * movementProgress; double adjustedMovement = blockCollision.computeCollisionOffset(x, y, z, boundingBox, axis, movement); - if (getAttachedBlockId(blockPos) == BlockStateValues.JAVA_SLIME_BLOCK_ID && adjustedMovement != movement) { + if (getAttachedBlockId(blockPos).is(Blocks.SLIME_BLOCK) && adjustedMovement != movement) { session.getPistonCache().setPlayerSlimeCollision(true); } return adjustedMovement; @@ -557,11 +558,11 @@ public class PistonBlockEntity { return false; } - private int getAttachedBlockId(Vector3i blockPos) { + private BlockState getAttachedBlockId(Vector3i blockPos) { if (blockPos.equals(getPistonHeadPos())) { - return BlockStateValues.getPistonHead(orientation); + return BlockState.of(BlockStateValues.getPistonHead(orientation)); } else { - return attachedBlocks.getOrDefault(blockPos, Block.JAVA_AIR_ID); + return attachedBlocks.getOrDefault(blockPos, BlockState.of(Block.JAVA_AIR_ID)); //FIXME } } @@ -582,12 +583,12 @@ public class PistonBlockEntity { playerBoundingBox.setSizeX(playerBoundingBox.getSizeX() + 0.5); playerBoundingBox.setSizeZ(playerBoundingBox.getSizeZ() + 0.5); } - attachedBlocks.forEach((blockPos, javaId) -> { + attachedBlocks.forEach((blockPos, state) -> { Vector3i newPos = blockPos.add(movement); if (SOLID_BOUNDING_BOX.checkIntersection(blockPos.toDouble(), playerBoundingBox) || SOLID_BOUNDING_BOX.checkIntersection(newPos.toDouble(), playerBoundingBox)) { session.getPistonCache().setPlayerCollided(true); - if (javaId == BlockStateValues.JAVA_SLIME_BLOCK_ID) { + if (state.is(Blocks.SLIME_BLOCK)) { session.getPistonCache().setPlayerSlimeCollision(true); } // Don't place moving blocks that collide with the player @@ -603,7 +604,7 @@ public class PistonBlockEntity { updateBlockPacket.setDataLayer(0); session.sendUpstreamPacket(updateBlockPacket); // Update moving block with correct details - BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(newPos, javaId, position), newPos); + BlockEntityUtils.updateBlockEntity(session, buildMovingBlockTag(newPos, state, position), newPos); }); } @@ -773,13 +774,13 @@ public class PistonBlockEntity { * Create a moving block tag of a block that will be moved by a piston * * @param position The ending position of the block (The location of the movingBlock block entity) - * @param javaId The Java Id of the block that is moving + * @param state The Java BlockState of the block that is moving * @param pistonPosition The position for the base of the piston that's moving the block * @return A moving block data tag */ - private NbtMap buildMovingBlockTag(Vector3i position, int javaId, Vector3i pistonPosition) { + private NbtMap buildMovingBlockTag(Vector3i position, BlockState state, Vector3i pistonPosition) { // Get Bedrock block state data - NbtMap movingBlock = session.getBlockMappings().getBedrockBlock(javaId).getState(); + NbtMap movingBlock = session.getBlockMappings().getBedrockBlock(state).getState(); NbtMapBuilder builder = NbtMap.builder() .putString("id", "MovingBlock") .putBoolean("expanding", action == PistonValueType.PUSHING) @@ -791,8 +792,8 @@ public class PistonBlockEntity { .putInt("x", position.getX()) .putInt("y", position.getY()) .putInt("z", position.getZ()); - if (PistonBlockEntityTranslator.isBlock(javaId)) { - builder.putCompound("movingEntity", PistonBlockEntityTranslator.getTag(javaId, position)); + if (state.block() instanceof PistonBlock piston) { + builder.putCompound("movingEntity", piston.createTag(session, position, state)); } return builder.build(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index 9cb3fb455..507d67ba5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; @@ -39,6 +38,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; @Translator(packet = BlockPickRequestPacket.class) public class BedrockBlockPickRequestTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index 36f1d3d65..b7201762f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -25,23 +25,25 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.BlockEventPacket; -import it.unimi.dsi.fastutil.objects.Object2IntMaps; import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.*; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; @Translator(packet = ClientboundBlockEventPacket.class) public class JavaBlockEventTranslator extends PacketTranslator { @@ -63,7 +65,7 @@ public class JavaBlockEventTranslator extends PacketTranslator { - blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState)); + blockEventPacket.setEventData(BlockState.of(blockState).getValue(Properties.NOTE)); session.sendUpstreamPacket(blockEventPacket); }); } else if (value instanceof PistonValue pistonValue) { @@ -90,7 +92,7 @@ public class JavaBlockEventTranslator extends PacketTranslator new PistonBlockEntity(session, pos, direction, true, true)); if (blockEntity.getAction() != action) { - blockEntity.setAction(action, Object2IntMaps.emptyMap()); + blockEntity.setAction(action, Object2ObjectMaps.emptyMap()); } } } else { @@ -110,11 +112,7 @@ public class JavaBlockEventTranslator extends PacketTranslator 0; case WEST -> 1; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index e54fe5896..bd7096d2b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -41,7 +41,6 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.BlockState; @@ -53,7 +52,7 @@ import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.BiomeTranslator; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; +import org.geysermc.geyser.translator.level.block.entity.BedrockChunkWantsBlockEntityTag; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.SkullBlockEntityTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -193,11 +192,12 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaId + state )); } } @@ -253,7 +253,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaPalette.idToState(paletteId) + state )); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java index ec7f45c8d..1462378e9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java @@ -31,25 +31,13 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; -import org.geysermc.geyser.translator.level.block.entity.FlowerPotBlockEntityTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import java.util.List; import java.util.Locale; import java.util.Map; public class BlockEntityUtils { - /** - * A list of all block entities that require the Java block state in order to fill out their block entity information. - * This list will be smaller with cache sections on as we don't need to double-cache data - */ - public static final List BEDROCK_ONLY_BLOCK_ENTITIES = List.of( - (BedrockOnlyBlockEntity) Registries.BLOCK_ENTITIES.get().get(BlockEntityType.CHEST), - new FlowerPotBlockEntityTranslator() - ); - /** * Contains a list of irregular block entity name translations that can't be fit into the regex */ 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 a1e956ace..5504d01a8 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -33,24 +33,19 @@ import lombok.experimental.UtilityClass; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2i; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.JavaDimension; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; @UtilityClass public class ChunkUtils { @@ -119,18 +114,30 @@ public class ChunkUtils { * @param position the position of the block */ public static void updateBlock(GeyserSession session, int blockState, Vector3i position) { - updateBlockClientSide(session, blockState, position); + updateBlockClientSide(session, BlockState.of(blockState), position); session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState); } + /** + * Sends a block update to the Bedrock client. If the platform does not have an integrated world manager, this also + * adds that block to the cache. + * @param session the Bedrock session to send/register the block to + * @param blockState the Java block state of the block + * @param position the position of the block + */ + public static void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { + updateBlockClientSide(session, blockState, position); + session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState.javaId()); + } + /** * Updates a block, but client-side only. */ - public static void updateBlockClientSide(GeyserSession session, int blockState, Vector3i position) { + public static void updateBlockClientSide(GeyserSession session, BlockState blockState, Vector3i position) { // Checks for item frames so they aren't tripped up and removed ItemFrameEntity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, position); if (itemFrameEntity != null) { - if (blockState == Block.JAVA_AIR_ID) { // Item frame is still present and no block overrides that; refresh it + if (blockState.is(Blocks.AIR)) { // Item frame is still present and no block overrides that; refresh it itemFrameEntity.updateBlock(true); // Still update the chunk cache with the new block if updateBlock is called return; @@ -138,91 +145,7 @@ public class ChunkUtils { // Otherwise, let's still store our reference to the item frame, but let the new block take precedence for now } - BlockDefinition definition = session.getBlockMappings().getBedrockBlock(blockState); - - int skullVariant = BlockStateValues.getSkullVariant(blockState); - if (skullVariant == -1) { - // Skull is gone - session.getSkullCache().removeSkull(position); - } else if (skullVariant == 3) { - // The changed block was a player skull so check if a custom block was defined for this skull - SkullCache.Skull skull = session.getSkullCache().updateSkull(position, blockState); - if (skull != null && skull.getBlockDefinition() != null) { - definition = skull.getBlockDefinition(); - } - } - - // Prevent moving_piston from being placed - // It's used for extending piston heads, but it isn't needed on Bedrock and causes pistons to flicker - if (!BlockStateValues.isMovingPiston(blockState)) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position); - updateBlockPacket.setDefinition(definition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - - UpdateBlockPacket waterPacket = new UpdateBlockPacket(); - waterPacket.setDataLayer(1); - waterPacket.setBlockPosition(position); - if (BlockRegistries.WATERLOGGED.get().get(blockState)) { - waterPacket.setDefinition(session.getBlockMappings().getBedrockWater()); - } else { - waterPacket.setDefinition(session.getBlockMappings().getBedrockAir()); - } - session.sendUpstreamPacket(waterPacket); - } - - // Extended collision boxes for custom blocks - if (!session.getBlockMappings().getExtendedCollisionBoxes().isEmpty()) { - int aboveBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() + 1, position.getZ()); - BlockDefinition aboveBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(blockState); - int belowBlock = session.getGeyser().getWorldManager().getBlockAt(session, position.getX(), position.getY() - 1, position.getZ()); - BlockDefinition belowBedrockExtendedCollisionDefinition = session.getBlockMappings().getExtendedCollisionBoxes().get(belowBlock); - if (belowBedrockExtendedCollisionDefinition != null && blockState == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position); - updateBlockPacket.setDefinition(belowBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBedrockExtendedCollisionDefinition != null && aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(aboveBedrockExtendedCollisionDefinition); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } else if (aboveBlock == Block.JAVA_AIR_ID) { - UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); - updateBlockPacket.setDataLayer(0); - updateBlockPacket.setBlockPosition(position.add(0, 1, 0)); - updateBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); - session.sendUpstreamPacket(updateBlockPacket); - } - } - - BlockStateValues.getLecternBookStates().handleBlockChange(session, blockState, position); - - // Iterates through all Bedrock-only block entity translators and determines if a manual block entity packet - // needs to be sent - for (BedrockOnlyBlockEntity bedrockOnlyBlockEntity : BlockEntityUtils.BEDROCK_ONLY_BLOCK_ENTITIES) { - if (bedrockOnlyBlockEntity.isBlock(blockState)) { - // Flower pots are block entities only in Bedrock and are not updated anywhere else like note blocks - bedrockOnlyBlockEntity.updateBlock(session, BlockState.of(blockState), position); //TODO blockState - 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); - } + blockState.block().updateBlock(session, blockState, position); } public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) {