diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch index b2ac6c60fe..1d84f433f3 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -122,7 +122,7 @@ + // Paper end + if (this.level == null) return null; + org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ()); -+ if (block.getType() == org.bukkit.Material.AIR) return null; ++ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists + org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper + if (state instanceof InventoryHolder) return (InventoryHolder) state; + return null; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java index 80bd6e8a6d..fe7e3e0628 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java @@ -20,7 +20,7 @@ import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CraftBlockEntityState extends CraftBlockState implements TileState { +public abstract class CraftBlockEntityState extends CraftBlockState implements TileState { // Paper - revert upstream's revert of the block state changes private final T tileEntity; private final T snapshot; @@ -196,14 +196,10 @@ public class CraftBlockEntityState extends CraftBlockStat } @Override - public CraftBlockEntityState copy() { - return new CraftBlockEntityState<>(this, null); - } + public abstract CraftBlockEntityState copy(); // Paper - make abstract @Override - public CraftBlockEntityState copy(Location location) { - return new CraftBlockEntityState<>(this, location); - } + public abstract CraftBlockEntityState copy(Location location); // Paper - make abstract // Paper start @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java index 1a8dcde39a..56453454cb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java @@ -22,6 +22,7 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity; import net.minecraft.world.level.block.entity.BellBlockEntity; import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; // Paper import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; import net.minecraft.world.level.block.entity.BrushableBlockEntity; import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity; @@ -88,9 +89,9 @@ public final class CraftBlockStates { private static class BlockEntityStateFactory> extends BlockStateFactory { private final BiFunction blockStateConstructor; - private final BiFunction tileEntityConstructor; + private final BlockEntityType tileEntityConstructor; // Paper - protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BiFunction tileEntityConstructor) { + protected BlockEntityStateFactory(Class blockStateType, BiFunction blockStateConstructor, BlockEntityType tileEntityConstructor) { // Paper super(blockStateType); this.blockStateConstructor = blockStateConstructor; this.tileEntityConstructor = tileEntityConstructor; @@ -107,7 +108,7 @@ public final class CraftBlockStates { } private T createTileEntity(BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData) { - return this.tileEntityConstructor.apply(blockPosition, blockData); + return this.tileEntityConstructor.create(blockPosition, blockData); // Paper } private B createBlockState(World world, T tileEntity) { @@ -119,233 +120,66 @@ public final class CraftBlockStates { private static final BlockStateFactory DEFAULT_FACTORY = new BlockStateFactory(CraftBlockState.class) { @Override public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) { - // SPIGOT-6754, SPIGOT-6817: Restore previous behaviour for tile entities with removed blocks (loot generation post-destroy) - if (tileEntity != null) { - // block with unhandled TileEntity: - return new CraftBlockEntityState<>(world, tileEntity); - } + // Paper - revert upstream's revert of the block state changes. Block entities that have already had the block type set to AIR are still valid, upstream decided to ignore them Preconditions.checkState(tileEntity == null, "Unexpected BlockState for %s", CraftBlockType.minecraftToBukkit(blockData.getBlock())); return new CraftBlockState(world, blockPosition, blockData); } }; + // Paper start + private static final Map, BlockStateFactory> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>(); + private static void register(BlockEntityType type, BlockStateFactory factory) { + FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory); + } + // Paper end static { - register( - Arrays.asList( - Material.ACACIA_SIGN, - Material.ACACIA_WALL_SIGN, - Material.BAMBOO_SIGN, - Material.BAMBOO_WALL_SIGN, - Material.BIRCH_SIGN, - Material.BIRCH_WALL_SIGN, - Material.CHERRY_SIGN, - Material.CHERRY_WALL_SIGN, - Material.CRIMSON_SIGN, - Material.CRIMSON_WALL_SIGN, - Material.DARK_OAK_SIGN, - Material.DARK_OAK_WALL_SIGN, - Material.JUNGLE_SIGN, - Material.JUNGLE_WALL_SIGN, - Material.MANGROVE_SIGN, - Material.MANGROVE_WALL_SIGN, - Material.OAK_SIGN, - Material.OAK_WALL_SIGN, - Material.PALE_OAK_SIGN, - Material.PALE_OAK_WALL_SIGN, - Material.SPRUCE_SIGN, - Material.SPRUCE_WALL_SIGN, - Material.WARPED_SIGN, - Material.WARPED_WALL_SIGN - ), CraftSign.class, CraftSign::new, SignBlockEntity::new - ); - - register( - Arrays.asList( - Material.ACACIA_HANGING_SIGN, - Material.ACACIA_WALL_HANGING_SIGN, - Material.BAMBOO_HANGING_SIGN, - Material.BAMBOO_WALL_HANGING_SIGN, - Material.BIRCH_HANGING_SIGN, - Material.BIRCH_WALL_HANGING_SIGN, - Material.CHERRY_HANGING_SIGN, - Material.CHERRY_WALL_HANGING_SIGN, - Material.CRIMSON_HANGING_SIGN, - Material.CRIMSON_WALL_HANGING_SIGN, - Material.DARK_OAK_HANGING_SIGN, - Material.DARK_OAK_WALL_HANGING_SIGN, - Material.JUNGLE_HANGING_SIGN, - Material.JUNGLE_WALL_HANGING_SIGN, - Material.MANGROVE_HANGING_SIGN, - Material.MANGROVE_WALL_HANGING_SIGN, - Material.OAK_HANGING_SIGN, - Material.OAK_WALL_HANGING_SIGN, - Material.PALE_OAK_HANGING_SIGN, - Material.PALE_OAK_WALL_HANGING_SIGN, - Material.SPRUCE_HANGING_SIGN, - Material.SPRUCE_WALL_HANGING_SIGN, - Material.WARPED_HANGING_SIGN, - Material.WARPED_WALL_HANGING_SIGN - ), CraftHangingSign.class, CraftHangingSign::new, HangingSignBlockEntity::new - ); - - register( - Arrays.asList( - Material.CREEPER_HEAD, - Material.CREEPER_WALL_HEAD, - Material.DRAGON_HEAD, - Material.DRAGON_WALL_HEAD, - Material.PIGLIN_HEAD, - Material.PIGLIN_WALL_HEAD, - Material.PLAYER_HEAD, - Material.PLAYER_WALL_HEAD, - Material.SKELETON_SKULL, - Material.SKELETON_WALL_SKULL, - Material.WITHER_SKELETON_SKULL, - Material.WITHER_SKELETON_WALL_SKULL, - Material.ZOMBIE_HEAD, - Material.ZOMBIE_WALL_HEAD - ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new - ); - - register( - Arrays.asList( - Material.COMMAND_BLOCK, - Material.REPEATING_COMMAND_BLOCK, - Material.CHAIN_COMMAND_BLOCK - ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new - ); - - register( - Arrays.asList( - Material.BLACK_BANNER, - Material.BLACK_WALL_BANNER, - Material.BLUE_BANNER, - Material.BLUE_WALL_BANNER, - Material.BROWN_BANNER, - Material.BROWN_WALL_BANNER, - Material.CYAN_BANNER, - Material.CYAN_WALL_BANNER, - Material.GRAY_BANNER, - Material.GRAY_WALL_BANNER, - Material.GREEN_BANNER, - Material.GREEN_WALL_BANNER, - Material.LIGHT_BLUE_BANNER, - Material.LIGHT_BLUE_WALL_BANNER, - Material.LIGHT_GRAY_BANNER, - Material.LIGHT_GRAY_WALL_BANNER, - Material.LIME_BANNER, - Material.LIME_WALL_BANNER, - Material.MAGENTA_BANNER, - Material.MAGENTA_WALL_BANNER, - Material.ORANGE_BANNER, - Material.ORANGE_WALL_BANNER, - Material.PINK_BANNER, - Material.PINK_WALL_BANNER, - Material.PURPLE_BANNER, - Material.PURPLE_WALL_BANNER, - Material.RED_BANNER, - Material.RED_WALL_BANNER, - Material.WHITE_BANNER, - Material.WHITE_WALL_BANNER, - Material.YELLOW_BANNER, - Material.YELLOW_WALL_BANNER - ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new - ); - - register( - Arrays.asList( - Material.SHULKER_BOX, - Material.WHITE_SHULKER_BOX, - Material.ORANGE_SHULKER_BOX, - Material.MAGENTA_SHULKER_BOX, - Material.LIGHT_BLUE_SHULKER_BOX, - Material.YELLOW_SHULKER_BOX, - Material.LIME_SHULKER_BOX, - Material.PINK_SHULKER_BOX, - Material.GRAY_SHULKER_BOX, - Material.LIGHT_GRAY_SHULKER_BOX, - Material.CYAN_SHULKER_BOX, - Material.PURPLE_SHULKER_BOX, - Material.BLUE_SHULKER_BOX, - Material.BROWN_SHULKER_BOX, - Material.GREEN_SHULKER_BOX, - Material.RED_SHULKER_BOX, - Material.BLACK_SHULKER_BOX - ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new - ); - - register( - Arrays.asList( - Material.BLACK_BED, - Material.BLUE_BED, - Material.BROWN_BED, - Material.CYAN_BED, - Material.GRAY_BED, - Material.GREEN_BED, - Material.LIGHT_BLUE_BED, - Material.LIGHT_GRAY_BED, - Material.LIME_BED, - Material.MAGENTA_BED, - Material.ORANGE_BED, - Material.PINK_BED, - Material.PURPLE_BED, - Material.RED_BED, - Material.WHITE_BED, - Material.YELLOW_BED - ), CraftBed.class, CraftBed::new, BedBlockEntity::new - ); - - register( - Arrays.asList( - Material.BEEHIVE, - Material.BEE_NEST - ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new - ); - - register( - Arrays.asList( - Material.CAMPFIRE, - Material.SOUL_CAMPFIRE - ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new - ); - - register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new); - register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new); - register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new); - register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new); - register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new); - register(Material.CHEST, CraftChest.class, CraftChest::new, ChestBlockEntity::new); - register(Material.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new, ChiseledBookShelfBlockEntity::new); - register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new); - register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new); - register(Material.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new, CreakingHeartBlockEntity::new); - register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new); - register(Material.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new, DecoratedPotBlockEntity::new); - register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new); - register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new); - register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantingTableBlockEntity::new); - register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new); - register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new); - register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new); - register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new); - register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new); - register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new); - register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new); - register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new); - register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new); - register(Material.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new, SculkCatalystBlockEntity::new); - register(Material.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new, CalibratedSculkSensorBlockEntity::new); - register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new); - register(Material.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new, SculkShriekerBlockEntity::new); - register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new); - register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new); - register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new); - register(Material.SUSPICIOUS_SAND, CraftSuspiciousSand.class, CraftSuspiciousSand::new, BrushableBlockEntity::new); - register(Material.SUSPICIOUS_GRAVEL, CraftBrushableBlock.class, CraftBrushableBlock::new, BrushableBlockEntity::new); - register(Material.TRAPPED_CHEST, CraftChest.class, CraftChest::new, TrappedChestBlockEntity::new); - register(Material.CRAFTER, CraftCrafter.class, CraftCrafter::new, CrafterBlockEntity::new); - register(Material.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new, TrialSpawnerBlockEntity::new); - register(Material.VAULT, CraftVault.class, CraftVault::new, VaultBlockEntity::new); + // Paper start - simplify + register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new); + register(BlockEntityType.HANGING_SIGN, CraftHangingSign.class, CraftHangingSign::new); + register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new); + register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new); + register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new); + register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new); + register(BlockEntityType.BED, CraftBed.class, CraftBed::new); + register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new); + register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new); + register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new); + register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new); + register(BlockEntityType.BELL, CraftBell.class, CraftBell::new); + register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new); + register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new); + register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new); + register(BlockEntityType.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new); + register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new); + register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new); + register(BlockEntityType.CREAKING_HEART, CraftCreakingHeart.class, CraftCreakingHeart::new); + register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new); + register(BlockEntityType.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new); + register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new); + register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new); + register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new); + register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new); + register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new); + register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new); + register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new); + register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new); + register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new); + register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new); + register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new); + register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new); + register(BlockEntityType.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new); + register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new); + register(BlockEntityType.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new); + register(BlockEntityType.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new); + register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new); + register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new); + register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new); + register(BlockEntityType.BRUSHABLE_BLOCK, CraftBrushableBlock.class, CraftBrushableBlock::new); // note: spigot still uses CraftSuspiciousSand impl for that block type + register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new); + register(BlockEntityType.CRAFTER, CraftCrafter.class, CraftCrafter::new); + register(BlockEntityType.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new); + register(BlockEntityType.VAULT, CraftVault.class, CraftVault::new); + // Paper end } private static void register(Material blockType, BlockStateFactory factory) { @@ -353,30 +187,33 @@ public final class CraftBlockStates { } private static > void register( - Material blockType, + net.minecraft.world.level.block.entity.BlockEntityType blockEntityType, // Paper Class blockStateType, - BiFunction blockStateConstructor, - BiFunction tileEntityConstructor + BiFunction blockStateConstructor // Paper ) { - CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor); - } - - private static > void register( - List blockTypes, - Class blockStateType, - BiFunction blockStateConstructor, - BiFunction tileEntityConstructor - ) { - BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor); - for (Material blockType : blockTypes) { - CraftBlockStates.register(blockType, factory); + // Paper start + BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType); // Paper + for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) { + CraftBlockStates.register(CraftBlockType.minecraftToBukkit(block), factory); } + CraftBlockStates.register(blockEntityType, factory); + // Paper end } private static BlockStateFactory getFactory(Material material) { return CraftBlockStates.FACTORIES.getOrDefault(material, CraftBlockStates.DEFAULT_FACTORY); } + // Paper start + private static BlockStateFactory getFactory(Material material, BlockEntityType type) { + if (type != null) { + return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material)); + } else { + return getFactory(material); + } + } + // Paper end + public static Class getBlockStateType(Material material) { Preconditions.checkNotNull(material, "material is null"); return CraftBlockStates.getFactory(material).blockStateType; @@ -392,6 +229,13 @@ public final class CraftBlockStates { return null; } + // Paper start + public static Class getBlockStateType(BlockEntityType blockEntityType) { + Preconditions.checkNotNull(blockEntityType, "blockEntityType is null"); + return CraftBlockStates.getFactory(null, blockEntityType).blockStateType; + } + // Paper end + public static BlockState getBlockState(Block block) { // Paper start return CraftBlockStates.getBlockState(block, true); @@ -459,7 +303,7 @@ public final class CraftBlockStates { if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) { factory = CraftBlockStates.DEFAULT_FACTORY; } else { - factory = CraftBlockStates.getFactory(material); + factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper } return factory.createBlockState(world, blockPosition, blockData, tileEntity); } @@ -478,6 +322,14 @@ public final class CraftBlockStates { return new CraftBlockState(CraftBlock.at(world, pos), flag); } + // Paper start + @Nullable + public static BlockEntityType getBlockEntityType(final Material material) { + final BlockStateFactory factory = org.bukkit.craftbukkit.block.CraftBlockStates.FACTORIES.get(material); + return factory instanceof final BlockEntityStateFactory blockEntityStateFactory ? blockEntityStateFactory.tileEntityConstructor : null; + } + // Paper end + private CraftBlockStates() { } } diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java index c032daa695..a9810c88e0 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java @@ -7,6 +7,7 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import org.bukkit.Material; import org.bukkit.support.environment.AllFeatures; import org.junit.jupiter.api.Test; @@ -42,4 +43,13 @@ public class BlockStateTest { } } } + + // Paper start + @Test + public void testBlockEntityTypes() { + for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + org.junit.jupiter.api.Assertions.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType)); + } + } + // Paper end }