2025-11-24 22:52:51 +03:00

188 lines
8.2 KiB
Java

/*
* 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<TurtleEggBlock> 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<TurtleEggBlock> 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<Block, BlockState> 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;
}
}