package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; 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.entity.CreakingHeartBlockEntity; 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.Property; import org.jetbrains.annotations.Nullable; public class CreakingHeartBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(CreakingHeartBlock::new); public static final EnumProperty AXIS = BlockStateProperties.AXIS; public static final EnumProperty CREAKING = BlockStateProperties.CREAKING; @Override public MapCodec codec() { return CODEC; } protected CreakingHeartBlock(BlockBehaviour.Properties properties) { super(properties); this.registerDefaultState(this.defaultBlockState().setValue(AXIS, Direction.Axis.Y).setValue(CREAKING, CreakingHeartBlock.CreakingHeartState.DISABLED)); } @Override public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return new CreakingHeartBlockEntity(pos, state); } @Nullable @Override public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) { if (level.isClientSide) { return null; } else { return state.getValue((Property)CREAKING) != CreakingHeartBlock.CreakingHeartState.DISABLED ? createTickerHelper(blockEntityType, BlockEntityType.CREAKING_HEART, CreakingHeartBlockEntity::serverTick) : null; } } public static boolean canSummonCreaking(Level level) { return level.dimensionType().natural() && level.isNight(); } @Override public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { if (canSummonCreaking(level)) { if (state.getValue(CREAKING) != CreakingHeartBlock.CreakingHeartState.DISABLED) { if (random.nextInt(16) == 0 && isSurroundedByLogs(level, pos)) { level.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.CREAKING_HEART_IDLE, SoundSource.BLOCKS, 1.0F, 1.0F, false); } } } } @Override protected BlockState updateShape( BlockState blockState, LevelReader levelReader, ScheduledTickAccess scheduledTickAccess, BlockPos blockPos, Direction direction, BlockPos blockPos2, BlockState blockState2, RandomSource randomSource ) { BlockState blockState3 = super.updateShape(blockState, levelReader, scheduledTickAccess, blockPos, direction, blockPos2, blockState2, randomSource); return updateState(blockState3, levelReader, blockPos); } private static BlockState updateState(BlockState blockState, LevelReader levelReader, BlockPos blockPos) { boolean bl = hasRequiredLogs(blockState, levelReader, blockPos); CreakingHeartBlock.CreakingHeartState creakingHeartState = blockState.getValue(CREAKING); return bl && creakingHeartState == CreakingHeartBlock.CreakingHeartState.DISABLED ? blockState.setValue(CREAKING, CreakingHeartBlock.CreakingHeartState.DORMANT) : blockState; } public static boolean hasRequiredLogs(BlockState blockState, LevelReader levelReader, BlockPos blockPos) { Direction.Axis axis = blockState.getValue(AXIS); for (Direction direction : axis.getDirections()) { BlockState blockState2 = levelReader.getBlockState(blockPos.relative(direction)); if (!blockState2.is(BlockTags.PALE_OAK_LOGS) || blockState2.getValue(AXIS) != axis) { return false; } } return true; } private static boolean isSurroundedByLogs(LevelAccessor levelAccessor, BlockPos blockPos) { for (Direction direction : Direction.values()) { BlockPos blockPos2 = blockPos.relative(direction); BlockState blockState = levelAccessor.getBlockState(blockPos2); if (!blockState.is(BlockTags.PALE_OAK_LOGS)) { return false; } } return true; } @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext context) { return updateState(this.defaultBlockState().setValue(AXIS, context.getClickedFace().getAxis()), context.getLevel(), context.getClickedPos()); } @Override protected RenderShape getRenderShape(BlockState state) { return RenderShape.MODEL; } @Override protected BlockState rotate(BlockState state, Rotation rotation) { return RotatedPillarBlock.rotatePillar(state, rotation); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(AXIS, CREAKING); } @Override protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { if (level.getBlockEntity(pos) instanceof CreakingHeartBlockEntity creakingHeartBlockEntity) { creakingHeartBlockEntity.removeProtector(null); } super.onRemove(state, level, pos, newState, movedByPiston); } @Override public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) { if (level.getBlockEntity(pos) instanceof CreakingHeartBlockEntity creakingHeartBlockEntity) { creakingHeartBlockEntity.removeProtector(player.damageSources().playerAttack(player)); } return super.playerWillDestroy(level, pos, state, player); } @Override protected boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) { if (state.getValue(CREAKING) != CreakingHeartBlock.CreakingHeartState.ACTIVE) { return 0; } else { return level.getBlockEntity(pos) instanceof CreakingHeartBlockEntity creakingHeartBlockEntity ? creakingHeartBlockEntity.getAnalogOutputSignal() : 0; } } public static enum CreakingHeartState implements StringRepresentable { DISABLED("disabled"), DORMANT("dormant"), ACTIVE("active"); private final String name; private CreakingHeartState(final String string2) { this.name = string2; } @Override public String getSerializedName() { return this.name; } } }