package net.minecraft.world.level.block; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.particles.TrailParticleOption; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.Difficulty; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.InsideBlockEffectApplier; import net.minecraft.world.entity.animal.Bee; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEvent.Context; import net.minecraft.world.phys.Vec3; public class EyeblossomBlock extends FlowerBlock { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group(Codec.BOOL.fieldOf("open").forGetter(eyeblossomBlock -> eyeblossomBlock.type.open), propertiesCodec()) .apply(instance, EyeblossomBlock::new) ); private static final int EYEBLOSSOM_XZ_RANGE = 3; private static final int EYEBLOSSOM_Y_RANGE = 2; private final EyeblossomBlock.Type type; @Override public MapCodec codec() { return CODEC; } public EyeblossomBlock(EyeblossomBlock.Type type, BlockBehaviour.Properties properties) { super(type.effect, type.effectDuration, properties); this.type = type; } public EyeblossomBlock(boolean open, BlockBehaviour.Properties properties) { super(EyeblossomBlock.Type.fromBoolean(open).effect, EyeblossomBlock.Type.fromBoolean(open).effectDuration, properties); this.type = EyeblossomBlock.Type.fromBoolean(open); } @Override public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { if (this.type.emitSounds() && random.nextInt(700) == 0) { BlockState blockState = level.getBlockState(pos.below()); if (blockState.is(Blocks.PALE_MOSS_BLOCK)) { level.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.EYEBLOSSOM_IDLE, SoundSource.AMBIENT, 1.0F, 1.0F, false); } } } @Override protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (this.tryChangingState(state, level, pos, random)) { level.playSound(null, pos, this.type.transform().longSwitchSound, SoundSource.BLOCKS, 1.0F, 1.0F); } super.randomTick(state, level, pos, random); } @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (this.tryChangingState(state, level, pos, random)) { level.playSound(null, pos, this.type.transform().shortSwitchSound, SoundSource.BLOCKS, 1.0F, 1.0F); } super.tick(state, level, pos, random); } private boolean tryChangingState(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (!level.dimensionType().natural()) { return false; } else if (CreakingHeartBlock.isNaturalNight(level) == this.type.open) { return false; } else { EyeblossomBlock.Type type = this.type.transform(); level.setBlock(pos, type.state(), 3); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, Context.of(state)); type.spawnTransformParticle(level, pos, random); BlockPos.betweenClosed(pos.offset(-3, -2, -3), pos.offset(3, 2, 3)).forEach(blockPos2 -> { BlockState blockState2 = level.getBlockState(blockPos2); if (blockState2 == state) { double d = Math.sqrt(pos.distSqr(blockPos2)); int i = random.nextIntBetweenInclusive((int)(d * 5.0), (int)(d * 10.0)); level.scheduleTick(blockPos2, state.getBlock(), i); } }); return true; } } @Override protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) { if (!level.isClientSide() && level.getDifficulty() != Difficulty.PEACEFUL && entity instanceof Bee bee && Bee.attractsBees(state) && !bee.hasEffect(MobEffects.POISON)) { bee.addEffect(this.getBeeInteractionEffect()); } } @Override public MobEffectInstance getBeeInteractionEffect() { return new MobEffectInstance(MobEffects.POISON, 25); } public static enum Type { OPEN(true, MobEffects.BLINDNESS, 11.0F, SoundEvents.EYEBLOSSOM_OPEN_LONG, SoundEvents.EYEBLOSSOM_OPEN, 16545810), CLOSED(false, MobEffects.NAUSEA, 7.0F, SoundEvents.EYEBLOSSOM_CLOSE_LONG, SoundEvents.EYEBLOSSOM_CLOSE, 6250335); final boolean open; final Holder effect; final float effectDuration; final SoundEvent longSwitchSound; final SoundEvent shortSwitchSound; private final int particleColor; private Type( final boolean open, final Holder effect, final float effectDuration, final SoundEvent longSwitchSound, final SoundEvent shortSwitchSound, final int particleColor ) { this.open = open; this.effect = effect; this.effectDuration = effectDuration; this.longSwitchSound = longSwitchSound; this.shortSwitchSound = shortSwitchSound; this.particleColor = particleColor; } public Block block() { return this.open ? Blocks.OPEN_EYEBLOSSOM : Blocks.CLOSED_EYEBLOSSOM; } public BlockState state() { return this.block().defaultBlockState(); } public EyeblossomBlock.Type transform() { return fromBoolean(!this.open); } public boolean emitSounds() { return this.open; } public static EyeblossomBlock.Type fromBoolean(boolean open) { return open ? OPEN : CLOSED; } public void spawnTransformParticle(ServerLevel level, BlockPos pos, RandomSource random) { Vec3 vec3 = pos.getCenter(); double d = 0.5 + random.nextDouble(); Vec3 vec32 = new Vec3(random.nextDouble() - 0.5, random.nextDouble() + 1.0, random.nextDouble() - 0.5); Vec3 vec33 = vec3.add(vec32.scale(d)); TrailParticleOption trailParticleOption = new TrailParticleOption(vec33, this.particleColor, (int)(20.0 * d)); level.sendParticles(trailParticleOption, vec3.x, vec3.y, vec3.z, 1, 0.0, 0.0, 0.0, 0.0); } public SoundEvent longSwitchSound() { return this.longSwitchSound; } } }