package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import java.util.List; import java.util.function.BiConsumer; import javax.annotation.Nullable; import net.minecraft.Util; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; import net.minecraft.tags.BlockTags; import net.minecraft.tags.EnchantmentTags; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.animal.Bee; import net.minecraft.world.entity.boss.wither.WitherBoss; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.item.PrimedTnt; import net.minecraft.world.entity.monster.Creeper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.WitherSkull; import net.minecraft.world.entity.vehicle.MinecartTNT; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.component.BlockItemStateProperties; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.entity.BeehiveBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.VoxelShape; public class BeehiveBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(BeehiveBlock::new); public static final EnumProperty FACING = HorizontalDirectionalBlock.FACING; public static final IntegerProperty HONEY_LEVEL = BlockStateProperties.LEVEL_HONEY; public static final int MAX_HONEY_LEVELS = 5; private static final int SHEARED_HONEYCOMB_COUNT = 3; @Override public MapCodec codec() { return CODEC; } public BeehiveBlock(BlockBehaviour.Properties p_49568_) { super(p_49568_); this.registerDefaultState(this.stateDefinition.any().setValue(HONEY_LEVEL, 0).setValue(FACING, Direction.NORTH)); } @Override protected boolean hasAnalogOutputSignal(BlockState p_49618_) { return true; } @Override protected int getAnalogOutputSignal(BlockState p_49620_, Level p_49621_, BlockPos p_49622_) { return p_49620_.getValue(HONEY_LEVEL); } @Override public void playerDestroy(Level p_49584_, Player p_49585_, BlockPos p_49586_, BlockState p_49587_, @Nullable BlockEntity p_49588_, ItemStack p_49589_) { super.playerDestroy(p_49584_, p_49585_, p_49586_, p_49587_, p_49588_, p_49589_); if (!p_49584_.isClientSide && p_49588_ instanceof BeehiveBlockEntity beehiveblockentity) { if (!EnchantmentHelper.hasTag(p_49589_, EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING)) { beehiveblockentity.emptyAllLivingFromHive(p_49585_, p_49587_, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); Containers.updateNeighboursAfterDestroy(p_49587_, p_49584_, p_49586_); this.angerNearbyBees(p_49584_, p_49586_); } CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer)p_49585_, p_49587_, p_49589_, beehiveblockentity.getOccupantCount()); } } @Override protected void onExplosionHit(BlockState p_365385_, ServerLevel p_361160_, BlockPos p_363432_, Explosion p_364892_, BiConsumer p_361789_) { super.onExplosionHit(p_365385_, p_361160_, p_363432_, p_364892_, p_361789_); this.angerNearbyBees(p_361160_, p_363432_); } private void angerNearbyBees(Level p_49650_, BlockPos p_49651_) { AABB aabb = new AABB(p_49651_).inflate(8.0, 6.0, 8.0); List list = p_49650_.getEntitiesOfClass(Bee.class, aabb); if (!list.isEmpty()) { List list1 = p_49650_.getEntitiesOfClass(Player.class, aabb); if (list1.isEmpty()) { return; } for (Bee bee : list) { if (bee.getTarget() == null) { Player player = Util.getRandom(list1, p_49650_.random); bee.setTarget(player); } } } } public static void dropHoneycomb(Level p_49601_, BlockPos p_49602_) { popResource(p_49601_, p_49602_, new ItemStack(Items.HONEYCOMB, 3)); } @Override protected InteractionResult useItemOn( ItemStack p_331014_, BlockState p_328141_, Level p_329187_, BlockPos p_335985_, Player p_336201_, InteractionHand p_333071_, BlockHitResult p_331246_ ) { int i = p_328141_.getValue(HONEY_LEVEL); boolean flag = false; if (i >= 5) { Item item = p_331014_.getItem(); if (p_331014_.is(Items.SHEARS)) { p_329187_.playSound( p_336201_, p_336201_.getX(), p_336201_.getY(), p_336201_.getZ(), SoundEvents.BEEHIVE_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F ); dropHoneycomb(p_329187_, p_335985_); p_331014_.hurtAndBreak(1, p_336201_, LivingEntity.getSlotForHand(p_333071_)); flag = true; p_329187_.gameEvent(p_336201_, GameEvent.SHEAR, p_335985_); } else if (p_331014_.is(Items.GLASS_BOTTLE)) { p_331014_.shrink(1); p_329187_.playSound( p_336201_, p_336201_.getX(), p_336201_.getY(), p_336201_.getZ(), SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F ); if (p_331014_.isEmpty()) { p_336201_.setItemInHand(p_333071_, new ItemStack(Items.HONEY_BOTTLE)); } else if (!p_336201_.getInventory().add(new ItemStack(Items.HONEY_BOTTLE))) { p_336201_.drop(new ItemStack(Items.HONEY_BOTTLE), false); } flag = true; p_329187_.gameEvent(p_336201_, GameEvent.FLUID_PICKUP, p_335985_); } if (!p_329187_.isClientSide() && flag) { p_336201_.awardStat(Stats.ITEM_USED.get(item)); } } if (flag) { if (!CampfireBlock.isSmokeyPos(p_329187_, p_335985_)) { if (this.hiveContainsBees(p_329187_, p_335985_)) { this.angerNearbyBees(p_329187_, p_335985_); } this.releaseBeesAndResetHoneyLevel(p_329187_, p_328141_, p_335985_, p_336201_, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); } else { this.resetHoneyLevel(p_329187_, p_328141_, p_335985_); } return InteractionResult.SUCCESS; } else { return super.useItemOn(p_331014_, p_328141_, p_329187_, p_335985_, p_336201_, p_333071_, p_331246_); } } private boolean hiveContainsBees(Level p_49655_, BlockPos p_49656_) { return p_49655_.getBlockEntity(p_49656_) instanceof BeehiveBlockEntity beehiveblockentity ? !beehiveblockentity.isEmpty() : false; } public void releaseBeesAndResetHoneyLevel(Level p_49595_, BlockState p_49596_, BlockPos p_49597_, @Nullable Player p_49598_, BeehiveBlockEntity.BeeReleaseStatus p_49599_) { this.resetHoneyLevel(p_49595_, p_49596_, p_49597_); if (p_49595_.getBlockEntity(p_49597_) instanceof BeehiveBlockEntity beehiveblockentity) { beehiveblockentity.emptyAllLivingFromHive(p_49598_, p_49596_, p_49599_); } } public void resetHoneyLevel(Level p_49591_, BlockState p_49592_, BlockPos p_49593_) { p_49591_.setBlock(p_49593_, p_49592_.setValue(HONEY_LEVEL, 0), 3); } @Override public void animateTick(BlockState p_220773_, Level p_220774_, BlockPos p_220775_, RandomSource p_220776_) { if (p_220773_.getValue(HONEY_LEVEL) >= 5) { for (int i = 0; i < p_220776_.nextInt(1) + 1; i++) { this.trySpawnDripParticles(p_220774_, p_220775_, p_220773_); } } } private void trySpawnDripParticles(Level p_49604_, BlockPos p_49605_, BlockState p_49606_) { if (p_49606_.getFluidState().isEmpty() && !(p_49604_.random.nextFloat() < 0.3F)) { VoxelShape voxelshape = p_49606_.getCollisionShape(p_49604_, p_49605_); double d0 = voxelshape.max(Direction.Axis.Y); if (d0 >= 1.0 && !p_49606_.is(BlockTags.IMPERMEABLE)) { double d1 = voxelshape.min(Direction.Axis.Y); if (d1 > 0.0) { this.spawnParticle(p_49604_, p_49605_, voxelshape, p_49605_.getY() + d1 - 0.05); } else { BlockPos blockpos = p_49605_.below(); BlockState blockstate = p_49604_.getBlockState(blockpos); VoxelShape voxelshape1 = blockstate.getCollisionShape(p_49604_, blockpos); double d2 = voxelshape1.max(Direction.Axis.Y); if ((d2 < 1.0 || !blockstate.isCollisionShapeFullBlock(p_49604_, blockpos)) && blockstate.getFluidState().isEmpty()) { this.spawnParticle(p_49604_, p_49605_, voxelshape, p_49605_.getY() - 0.05); } } } } } private void spawnParticle(Level p_49613_, BlockPos p_49614_, VoxelShape p_49615_, double p_49616_) { this.spawnFluidParticle( p_49613_, p_49614_.getX() + p_49615_.min(Direction.Axis.X), p_49614_.getX() + p_49615_.max(Direction.Axis.X), p_49614_.getZ() + p_49615_.min(Direction.Axis.Z), p_49614_.getZ() + p_49615_.max(Direction.Axis.Z), p_49616_ ); } private void spawnFluidParticle(Level p_49577_, double p_49578_, double p_49579_, double p_49580_, double p_49581_, double p_49582_) { p_49577_.addParticle( ParticleTypes.DRIPPING_HONEY, Mth.lerp(p_49577_.random.nextDouble(), p_49578_, p_49579_), p_49582_, Mth.lerp(p_49577_.random.nextDouble(), p_49580_, p_49581_), 0.0, 0.0, 0.0 ); } @Override public BlockState getStateForPlacement(BlockPlaceContext p_49573_) { return this.defaultBlockState().setValue(FACING, p_49573_.getHorizontalDirection().getOpposite()); } @Override protected void createBlockStateDefinition(StateDefinition.Builder p_49646_) { p_49646_.add(HONEY_LEVEL, FACING); } @Nullable @Override public BlockEntity newBlockEntity(BlockPos p_152184_, BlockState p_152185_) { return new BeehiveBlockEntity(p_152184_, p_152185_); } @Nullable @Override public BlockEntityTicker getTicker(Level p_152180_, BlockState p_152181_, BlockEntityType p_152182_) { return p_152180_.isClientSide ? null : createTickerHelper(p_152182_, BlockEntityType.BEEHIVE, BeehiveBlockEntity::serverTick); } @Override public BlockState playerWillDestroy(Level p_49608_, BlockPos p_49609_, BlockState p_49610_, Player p_49611_) { if (p_49608_ instanceof ServerLevel serverlevel && p_49611_.preventsBlockDrops() && serverlevel.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS) && p_49608_.getBlockEntity(p_49609_) instanceof BeehiveBlockEntity beehiveblockentity) { int i = p_49610_.getValue(HONEY_LEVEL); boolean flag = !beehiveblockentity.isEmpty(); if (flag || i > 0) { ItemStack itemstack = new ItemStack(this); itemstack.applyComponents(beehiveblockentity.collectComponents()); itemstack.set(DataComponents.BLOCK_STATE, BlockItemStateProperties.EMPTY.with(HONEY_LEVEL, i)); ItemEntity itementity = new ItemEntity(p_49608_, p_49609_.getX(), p_49609_.getY(), p_49609_.getZ(), itemstack); itementity.setDefaultPickUpDelay(); p_49608_.addFreshEntity(itementity); } } return super.playerWillDestroy(p_49608_, p_49609_, p_49610_, p_49611_); } @Override protected List getDrops(BlockState p_49636_, LootParams.Builder p_287581_) { Entity entity = p_287581_.getOptionalParameter(LootContextParams.THIS_ENTITY); if (entity instanceof PrimedTnt || entity instanceof Creeper || entity instanceof WitherSkull || entity instanceof WitherBoss || entity instanceof MinecartTNT) { BlockEntity blockentity = p_287581_.getOptionalParameter(LootContextParams.BLOCK_ENTITY); if (blockentity instanceof BeehiveBlockEntity beehiveblockentity) { beehiveblockentity.emptyAllLivingFromHive(null, p_49636_, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); } } return super.getDrops(p_49636_, p_287581_); } @Override protected ItemStack getCloneItemStack(LevelReader p_375896_, BlockPos p_377793_, BlockState p_377589_, boolean p_376286_) { ItemStack itemstack = super.getCloneItemStack(p_375896_, p_377793_, p_377589_, p_376286_); if (p_376286_) { itemstack.set(DataComponents.BLOCK_STATE, BlockItemStateProperties.EMPTY.with(HONEY_LEVEL, p_377589_.getValue(HONEY_LEVEL))); } return itemstack; } @Override protected BlockState updateShape( BlockState p_49639_, LevelReader p_364129_, ScheduledTickAccess p_367483_, BlockPos p_49643_, Direction p_49640_, BlockPos p_49644_, BlockState p_49641_, RandomSource p_365194_ ) { if (p_364129_.getBlockState(p_49644_).getBlock() instanceof FireBlock && p_364129_.getBlockEntity(p_49643_) instanceof BeehiveBlockEntity beehiveblockentity) { beehiveblockentity.emptyAllLivingFromHive(null, p_49639_, BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY); } return super.updateShape(p_49639_, p_364129_, p_367483_, p_49643_, p_49640_, p_49644_, p_49641_, p_365194_); } @Override public BlockState rotate(BlockState p_309863_, Rotation p_310613_) { return p_309863_.setValue(FACING, p_310613_.rotate(p_309863_.getValue(FACING))); } @Override public BlockState mirror(BlockState p_311137_, Mirror p_310463_) { return p_311137_.rotate(p_310463_.getRotation(p_311137_.getValue(FACING))); } }