/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.serialization.MapCodec * org.jspecify.annotations.Nullable */ package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ambient.Bat; import net.minecraft.world.entity.animal.Turtle; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; 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.IntegerProperty; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import org.jspecify.annotations.Nullable; public class TurtleEggBlock extends Block { public static final MapCodec CODEC = TurtleEggBlock.simpleCodec(TurtleEggBlock::new); public static final IntegerProperty HATCH = BlockStateProperties.HATCH; public static final IntegerProperty EGGS = BlockStateProperties.EGGS; public static final int MAX_HATCH_LEVEL = 2; public static final int MIN_EGGS = 1; public static final int MAX_EGGS = 4; private static final VoxelShape SHAPE_SINGLE = Block.box(3.0, 0.0, 3.0, 12.0, 7.0, 12.0); private static final VoxelShape SHAPE_MULTIPLE = Block.column(14.0, 0.0, 7.0); public MapCodec codec() { return CODEC; } public TurtleEggBlock(BlockBehaviour.Properties properties) { super(properties); this.registerDefaultState((BlockState)((BlockState)((BlockState)this.stateDefinition.any()).setValue(HATCH, 0)).setValue(EGGS, 1)); } @Override public void stepOn(Level level, BlockPos pos, BlockState onState, Entity entity) { if (!entity.isSteppingCarefully()) { this.destroyEgg(level, onState, pos, entity, 100); } super.stepOn(level, pos, onState, entity); } @Override public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, double fallDistance) { if (!(entity instanceof Zombie)) { this.destroyEgg(level, state, pos, entity, 3); } super.fallOn(level, state, pos, entity, fallDistance); } private void destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int randomness) { ServerLevel serverLevel; if (state.is(Blocks.TURTLE_EGG) && level instanceof ServerLevel && this.canDestroyEgg(serverLevel = (ServerLevel)level, entity) && level.random.nextInt(randomness) == 0) { this.decreaseEggs(serverLevel, pos, state); } } private void decreaseEggs(Level level, BlockPos pos, BlockState state) { level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7f, 0.9f + level.random.nextFloat() * 0.2f); int numberOfEggs = state.getValue(EGGS); if (numberOfEggs <= 1) { level.destroyBlock(pos, false); } else { level.setBlock(pos, (BlockState)state.setValue(EGGS, numberOfEggs - 1), 2); level.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(state)); level.levelEvent(2001, pos, Block.getId(state)); } } @Override protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (this.shouldUpdateHatchLevel(level, pos) && TurtleEggBlock.onSand(level, pos)) { int hatch = state.getValue(HATCH); if (hatch < 2) { level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7f, 0.9f + random.nextFloat() * 0.2f); level.setBlock(pos, (BlockState)state.setValue(HATCH, hatch + 1), 2); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); } else { level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.7f, 0.9f + random.nextFloat() * 0.2f); level.removeBlock(pos, false); level.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(state)); for (int i = 0; i < state.getValue(EGGS); ++i) { level.levelEvent(2001, pos, Block.getId(state)); Turtle turtle = EntityType.TURTLE.create(level, EntitySpawnReason.BREEDING); if (turtle == null) continue; turtle.setAge(-24000); turtle.setHomePos(pos); turtle.snapTo((double)pos.getX() + 0.3 + (double)i * 0.2, pos.getY(), (double)pos.getZ() + 0.3, 0.0f, 0.0f); level.addFreshEntity(turtle); } } } } public static boolean onSand(BlockGetter level, BlockPos pos) { return TurtleEggBlock.isSand(level, pos.below()); } public static boolean isSand(BlockGetter level, BlockPos pos) { return level.getBlockState(pos).is(BlockTags.SAND); } @Override protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { if (TurtleEggBlock.onSand(level, pos) && !level.isClientSide()) { level.levelEvent(2012, pos, 15); } } private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) { float chance = level.environmentAttributes().getValue(EnvironmentAttributes.TURTLE_EGG_HATCH_CHANCE, pos).floatValue(); return chance > 0.0f && level.random.nextFloat() < chance; } @Override public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack destroyedWith) { super.playerDestroy(level, player, pos, state, blockEntity, destroyedWith); this.decreaseEggs(level, pos, state); } @Override protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) { if (!context.isSecondaryUseActive() && context.getItemInHand().is(this.asItem()) && state.getValue(EGGS) < 4) { return true; } return super.canBeReplaced(state, context); } @Override public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) { BlockState state = context.getLevel().getBlockState(context.getClickedPos()); if (state.is(this)) { return (BlockState)state.setValue(EGGS, Math.min(4, state.getValue(EGGS) + 1)); } return super.getStateForPlacement(context); } @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return state.getValue(EGGS) == 1 ? SHAPE_SINGLE : SHAPE_MULTIPLE; } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(HATCH, EGGS); } private boolean canDestroyEgg(ServerLevel level, Entity entity) { if (entity instanceof Turtle || entity instanceof Bat) { return false; } if (entity instanceof LivingEntity) { return entity instanceof Player || level.getGameRules().get(GameRules.MOB_GRIEFING) != false; } return false; } }