minecraft-src/net/minecraft/world/level/block/LayeredCauldronBlock.java
2025-09-18 12:27:44 +00:00

137 lines
5.5 KiB
Java

package net.minecraft.world.level.block;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.cauldron.CauldronInteraction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.InsideBlockEffectApplier;
import net.minecraft.world.entity.InsideBlockEffectType;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
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.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class LayeredCauldronBlock extends AbstractCauldronBlock {
public static final MapCodec<LayeredCauldronBlock> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
Biome.Precipitation.CODEC.fieldOf("precipitation").forGetter(layeredCauldronBlock -> layeredCauldronBlock.precipitationType),
CauldronInteraction.CODEC.fieldOf("interactions").forGetter(layeredCauldronBlock -> layeredCauldronBlock.interactions),
propertiesCodec()
)
.apply(instance, LayeredCauldronBlock::new)
);
public static final int MIN_FILL_LEVEL = 1;
public static final int MAX_FILL_LEVEL = 3;
public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_CAULDRON;
private static final int BASE_CONTENT_HEIGHT = 6;
private static final double HEIGHT_PER_LEVEL = 3.0;
private static final VoxelShape[] FILLED_SHAPES = Util.make(
() -> Block.boxes(2, i -> Shapes.or(AbstractCauldronBlock.SHAPE, Block.column(12.0, 4.0, getPixelContentHeight(i + 1))))
);
private final Biome.Precipitation precipitationType;
@Override
public MapCodec<LayeredCauldronBlock> codec() {
return CODEC;
}
public LayeredCauldronBlock(Biome.Precipitation precipitationType, CauldronInteraction.InteractionMap interactions, BlockBehaviour.Properties properties) {
super(properties, interactions);
this.precipitationType = precipitationType;
this.registerDefaultState(this.stateDefinition.any().setValue(LEVEL, 1));
}
@Override
public boolean isFull(BlockState state) {
return (Integer)state.getValue(LEVEL) == 3;
}
@Override
protected boolean canReceiveStalactiteDrip(Fluid fluid) {
return fluid == Fluids.WATER && this.precipitationType == Biome.Precipitation.RAIN;
}
@Override
protected double getContentHeight(BlockState state) {
return getPixelContentHeight((Integer)state.getValue(LEVEL)) / 16.0;
}
private static double getPixelContentHeight(int level) {
return 6.0 + level * 3.0;
}
@Override
protected VoxelShape getEntityInsideCollisionShape(BlockState state, BlockGetter level, BlockPos pos, Entity entity) {
return FILLED_SHAPES[state.getValue(LEVEL) - 1];
}
@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) {
if (level instanceof ServerLevel serverLevel) {
BlockPos blockPos = pos.immutable();
effectApplier.runBefore(InsideBlockEffectType.EXTINGUISH, entityx -> {
if (entityx.isOnFire() && entityx.mayInteract(serverLevel, blockPos)) {
this.handleEntityOnFireInside(state, level, blockPos);
}
});
}
effectApplier.apply(InsideBlockEffectType.EXTINGUISH);
}
private void handleEntityOnFireInside(BlockState state, Level level, BlockPos pos) {
if (this.precipitationType == Biome.Precipitation.SNOW) {
lowerFillLevel(Blocks.WATER_CAULDRON.defaultBlockState().setValue(LEVEL, (Integer)state.getValue(LEVEL)), level, pos);
} else {
lowerFillLevel(state, level, pos);
}
}
public static void lowerFillLevel(BlockState state, Level level, BlockPos pos) {
int i = (Integer)state.getValue(LEVEL) - 1;
BlockState blockState = i == 0 ? Blocks.CAULDRON.defaultBlockState() : state.setValue(LEVEL, i);
level.setBlockAndUpdate(pos, blockState);
level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
}
@Override
public void handlePrecipitation(BlockState state, Level level, BlockPos pos, Biome.Precipitation precipitation) {
if (CauldronBlock.shouldHandlePrecipitation(level, precipitation) && (Integer)state.getValue(LEVEL) != 3 && precipitation == this.precipitationType) {
BlockState blockState = state.cycle(LEVEL);
level.setBlockAndUpdate(pos, blockState);
level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
}
}
@Override
protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) {
return (Integer)state.getValue(LEVEL);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LEVEL);
}
@Override
protected void receiveStalactiteDrip(BlockState state, Level level, BlockPos pos, Fluid fluid) {
if (!this.isFull(state)) {
BlockState blockState = state.setValue(LEVEL, (Integer)state.getValue(LEVEL) + 1);
level.setBlockAndUpdate(pos, blockState);
level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
level.levelEvent(1047, pos, 0);
}
}
}