Code/net/minecraft/world/level/block/ComposterBlock.java

470 lines
18 KiB
Java

package net.minecraft.world.level.block;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.WorldlyContainerHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
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.pathfinder.PathComputationType;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class ComposterBlock extends Block implements WorldlyContainerHolder {
public static final MapCodec<ComposterBlock> CODEC = simpleCodec(ComposterBlock::new);
public static final int READY = 8;
public static final int MIN_LEVEL = 0;
public static final int MAX_LEVEL = 7;
public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_COMPOSTER;
public static final Object2FloatMap<ItemLike> COMPOSTABLES = new Object2FloatOpenHashMap<>();
private static final int HOLE_WIDTH = 12;
private static final VoxelShape[] SHAPES = Util.make(
() -> {
VoxelShape[] avoxelshape = Block.boxes(
8,
p_390931_ -> Shapes.join(Shapes.block(), Block.column(12.0, Math.clamp((long)(1 + p_390931_ * 2), 2, 16), 16.0), BooleanOp.ONLY_FIRST)
);
avoxelshape[8] = avoxelshape[7];
return avoxelshape;
}
);
@Override
public MapCodec<ComposterBlock> codec() {
return CODEC;
}
public static void bootStrap() {
COMPOSTABLES.defaultReturnValue(-1.0F);
float f = 0.3F;
float f1 = 0.5F;
float f2 = 0.65F;
float f3 = 0.85F;
float f4 = 1.0F;
add(0.3F, Items.JUNGLE_LEAVES);
add(0.3F, Items.OAK_LEAVES);
add(0.3F, Items.SPRUCE_LEAVES);
add(0.3F, Items.DARK_OAK_LEAVES);
add(0.3F, Items.PALE_OAK_LEAVES);
add(0.3F, Items.ACACIA_LEAVES);
add(0.3F, Items.CHERRY_LEAVES);
add(0.3F, Items.BIRCH_LEAVES);
add(0.3F, Items.AZALEA_LEAVES);
add(0.3F, Items.MANGROVE_LEAVES);
add(0.3F, Items.OAK_SAPLING);
add(0.3F, Items.SPRUCE_SAPLING);
add(0.3F, Items.BIRCH_SAPLING);
add(0.3F, Items.JUNGLE_SAPLING);
add(0.3F, Items.ACACIA_SAPLING);
add(0.3F, Items.CHERRY_SAPLING);
add(0.3F, Items.DARK_OAK_SAPLING);
add(0.3F, Items.PALE_OAK_SAPLING);
add(0.3F, Items.MANGROVE_PROPAGULE);
add(0.3F, Items.BEETROOT_SEEDS);
add(0.3F, Items.DRIED_KELP);
add(0.3F, Items.SHORT_GRASS);
add(0.3F, Items.KELP);
add(0.3F, Items.MELON_SEEDS);
add(0.3F, Items.PUMPKIN_SEEDS);
add(0.3F, Items.SEAGRASS);
add(0.3F, Items.SWEET_BERRIES);
add(0.3F, Items.GLOW_BERRIES);
add(0.3F, Items.WHEAT_SEEDS);
add(0.3F, Items.MOSS_CARPET);
add(0.3F, Items.PALE_MOSS_CARPET);
add(0.3F, Items.PALE_HANGING_MOSS);
add(0.3F, Items.PINK_PETALS);
add(0.3F, Items.WILDFLOWERS);
add(0.3F, Items.LEAF_LITTER);
add(0.3F, Items.SMALL_DRIPLEAF);
add(0.3F, Items.HANGING_ROOTS);
add(0.3F, Items.MANGROVE_ROOTS);
add(0.3F, Items.TORCHFLOWER_SEEDS);
add(0.3F, Items.PITCHER_POD);
add(0.3F, Items.FIREFLY_BUSH);
add(0.3F, Items.BUSH);
add(0.3F, Items.CACTUS_FLOWER);
add(0.3F, Items.DRY_SHORT_GRASS);
add(0.3F, Items.DRY_TALL_GRASS);
add(0.5F, Items.DRIED_KELP_BLOCK);
add(0.5F, Items.TALL_GRASS);
add(0.5F, Items.FLOWERING_AZALEA_LEAVES);
add(0.5F, Items.CACTUS);
add(0.5F, Items.SUGAR_CANE);
add(0.5F, Items.VINE);
add(0.5F, Items.NETHER_SPROUTS);
add(0.5F, Items.WEEPING_VINES);
add(0.5F, Items.TWISTING_VINES);
add(0.5F, Items.MELON_SLICE);
add(0.5F, Items.GLOW_LICHEN);
add(0.65F, Items.SEA_PICKLE);
add(0.65F, Items.LILY_PAD);
add(0.65F, Items.PUMPKIN);
add(0.65F, Items.CARVED_PUMPKIN);
add(0.65F, Items.MELON);
add(0.65F, Items.APPLE);
add(0.65F, Items.BEETROOT);
add(0.65F, Items.CARROT);
add(0.65F, Items.COCOA_BEANS);
add(0.65F, Items.POTATO);
add(0.65F, Items.WHEAT);
add(0.65F, Items.BROWN_MUSHROOM);
add(0.65F, Items.RED_MUSHROOM);
add(0.65F, Items.MUSHROOM_STEM);
add(0.65F, Items.CRIMSON_FUNGUS);
add(0.65F, Items.WARPED_FUNGUS);
add(0.65F, Items.NETHER_WART);
add(0.65F, Items.CRIMSON_ROOTS);
add(0.65F, Items.WARPED_ROOTS);
add(0.65F, Items.SHROOMLIGHT);
add(0.65F, Items.DANDELION);
add(0.65F, Items.POPPY);
add(0.65F, Items.BLUE_ORCHID);
add(0.65F, Items.ALLIUM);
add(0.65F, Items.AZURE_BLUET);
add(0.65F, Items.RED_TULIP);
add(0.65F, Items.ORANGE_TULIP);
add(0.65F, Items.WHITE_TULIP);
add(0.65F, Items.PINK_TULIP);
add(0.65F, Items.OXEYE_DAISY);
add(0.65F, Items.CORNFLOWER);
add(0.65F, Items.LILY_OF_THE_VALLEY);
add(0.65F, Items.WITHER_ROSE);
add(0.65F, Items.OPEN_EYEBLOSSOM);
add(0.65F, Items.CLOSED_EYEBLOSSOM);
add(0.65F, Items.FERN);
add(0.65F, Items.SUNFLOWER);
add(0.65F, Items.LILAC);
add(0.65F, Items.ROSE_BUSH);
add(0.65F, Items.PEONY);
add(0.65F, Items.LARGE_FERN);
add(0.65F, Items.SPORE_BLOSSOM);
add(0.65F, Items.AZALEA);
add(0.65F, Items.MOSS_BLOCK);
add(0.65F, Items.PALE_MOSS_BLOCK);
add(0.65F, Items.BIG_DRIPLEAF);
add(0.85F, Items.HAY_BLOCK);
add(0.85F, Items.BROWN_MUSHROOM_BLOCK);
add(0.85F, Items.RED_MUSHROOM_BLOCK);
add(0.85F, Items.NETHER_WART_BLOCK);
add(0.85F, Items.WARPED_WART_BLOCK);
add(0.85F, Items.FLOWERING_AZALEA);
add(0.85F, Items.BREAD);
add(0.85F, Items.BAKED_POTATO);
add(0.85F, Items.COOKIE);
add(0.85F, Items.TORCHFLOWER);
add(0.85F, Items.PITCHER_PLANT);
add(1.0F, Items.CAKE);
add(1.0F, Items.PUMPKIN_PIE);
}
private static void add(float p_51921_, ItemLike p_51922_) {
COMPOSTABLES.put(p_51922_.asItem(), p_51921_);
}
public ComposterBlock(BlockBehaviour.Properties p_51919_) {
super(p_51919_);
this.registerDefaultState(this.stateDefinition.any().setValue(LEVEL, 0));
}
public static void handleFill(Level p_51924_, BlockPos p_51925_, boolean p_51926_) {
BlockState blockstate = p_51924_.getBlockState(p_51925_);
p_51924_.playLocalSound(p_51925_, p_51926_ ? SoundEvents.COMPOSTER_FILL_SUCCESS : SoundEvents.COMPOSTER_FILL, SoundSource.BLOCKS, 1.0F, 1.0F, false);
double d0 = blockstate.getShape(p_51924_, p_51925_).max(Direction.Axis.Y, 0.5, 0.5) + 0.03125;
double d1 = 2.0;
double d2 = 0.1875;
double d3 = 0.625;
RandomSource randomsource = p_51924_.getRandom();
for (int i = 0; i < 10; i++) {
double d4 = randomsource.nextGaussian() * 0.02;
double d5 = randomsource.nextGaussian() * 0.02;
double d6 = randomsource.nextGaussian() * 0.02;
p_51924_.addParticle(
ParticleTypes.COMPOSTER,
p_51925_.getX() + 0.1875 + 0.625 * randomsource.nextFloat(),
p_51925_.getY() + d0 + randomsource.nextFloat() * (1.0 - d0),
p_51925_.getZ() + 0.1875 + 0.625 * randomsource.nextFloat(),
d4,
d5,
d6
);
}
}
@Override
protected VoxelShape getShape(BlockState p_51973_, BlockGetter p_51974_, BlockPos p_51975_, CollisionContext p_51976_) {
return SHAPES[p_51973_.getValue(LEVEL)];
}
@Override
protected VoxelShape getInteractionShape(BlockState p_51969_, BlockGetter p_51970_, BlockPos p_51971_) {
return Shapes.block();
}
@Override
protected VoxelShape getCollisionShape(BlockState p_51990_, BlockGetter p_51991_, BlockPos p_51992_, CollisionContext p_51993_) {
return SHAPES[0];
}
@Override
protected void onPlace(BlockState p_51978_, Level p_51979_, BlockPos p_51980_, BlockState p_51981_, boolean p_51982_) {
if (p_51978_.getValue(LEVEL) == 7) {
p_51979_.scheduleTick(p_51980_, p_51978_.getBlock(), 20);
}
}
@Override
protected InteractionResult useItemOn(
ItemStack p_336075_, BlockState p_334681_, Level p_333427_, BlockPos p_334604_, Player p_334719_, InteractionHand p_335310_, BlockHitResult p_332770_
) {
int i = p_334681_.getValue(LEVEL);
if (i < 8 && COMPOSTABLES.containsKey(p_336075_.getItem())) {
if (i < 7 && !p_333427_.isClientSide) {
BlockState blockstate = addItem(p_334719_, p_334681_, p_333427_, p_334604_, p_336075_);
p_333427_.levelEvent(1500, p_334604_, p_334681_ != blockstate ? 1 : 0);
p_334719_.awardStat(Stats.ITEM_USED.get(p_336075_.getItem()));
p_336075_.consume(1, p_334719_);
}
return InteractionResult.SUCCESS;
} else {
return super.useItemOn(p_336075_, p_334681_, p_333427_, p_334604_, p_334719_, p_335310_, p_332770_);
}
}
@Override
protected InteractionResult useWithoutItem(BlockState p_328272_, Level p_327852_, BlockPos p_336294_, Player p_330986_, BlockHitResult p_332650_) {
int i = p_328272_.getValue(LEVEL);
if (i == 8) {
extractProduce(p_330986_, p_328272_, p_327852_, p_336294_);
return InteractionResult.SUCCESS;
} else {
return InteractionResult.PASS;
}
}
public static BlockState insertItem(Entity p_270919_, BlockState p_270087_, ServerLevel p_270284_, ItemStack p_270253_, BlockPos p_270678_) {
int i = p_270087_.getValue(LEVEL);
if (i < 7 && COMPOSTABLES.containsKey(p_270253_.getItem())) {
BlockState blockstate = addItem(p_270919_, p_270087_, p_270284_, p_270678_, p_270253_);
p_270253_.shrink(1);
return blockstate;
} else {
return p_270087_;
}
}
public static BlockState extractProduce(Entity p_270467_, BlockState p_51999_, Level p_52000_, BlockPos p_52001_) {
if (!p_52000_.isClientSide) {
Vec3 vec3 = Vec3.atLowerCornerWithOffset(p_52001_, 0.5, 1.01, 0.5).offsetRandom(p_52000_.random, 0.7F);
ItemEntity itementity = new ItemEntity(p_52000_, vec3.x(), vec3.y(), vec3.z(), new ItemStack(Items.BONE_MEAL));
itementity.setDefaultPickUpDelay();
p_52000_.addFreshEntity(itementity);
}
BlockState blockstate = empty(p_270467_, p_51999_, p_52000_, p_52001_);
p_52000_.playSound(null, p_52001_, SoundEvents.COMPOSTER_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
return blockstate;
}
static BlockState empty(@Nullable Entity p_270236_, BlockState p_270873_, LevelAccessor p_270963_, BlockPos p_270211_) {
BlockState blockstate = p_270873_.setValue(LEVEL, 0);
p_270963_.setBlock(p_270211_, blockstate, 3);
p_270963_.gameEvent(GameEvent.BLOCK_CHANGE, p_270211_, GameEvent.Context.of(p_270236_, blockstate));
return blockstate;
}
static BlockState addItem(@Nullable Entity p_270464_, BlockState p_270603_, LevelAccessor p_270151_, BlockPos p_270547_, ItemStack p_270354_) {
int i = p_270603_.getValue(LEVEL);
float f = COMPOSTABLES.getFloat(p_270354_.getItem());
if ((i != 0 || !(f > 0.0F)) && !(p_270151_.getRandom().nextDouble() < f)) {
return p_270603_;
} else {
int j = i + 1;
BlockState blockstate = p_270603_.setValue(LEVEL, j);
p_270151_.setBlock(p_270547_, blockstate, 3);
p_270151_.gameEvent(GameEvent.BLOCK_CHANGE, p_270547_, GameEvent.Context.of(p_270464_, blockstate));
if (j == 7) {
p_270151_.scheduleTick(p_270547_, p_270603_.getBlock(), 20);
}
return blockstate;
}
}
@Override
protected void tick(BlockState p_221015_, ServerLevel p_221016_, BlockPos p_221017_, RandomSource p_221018_) {
if (p_221015_.getValue(LEVEL) == 7) {
p_221016_.setBlock(p_221017_, p_221015_.cycle(LEVEL), 3);
p_221016_.playSound(null, p_221017_, SoundEvents.COMPOSTER_READY, SoundSource.BLOCKS, 1.0F, 1.0F);
}
}
@Override
protected boolean hasAnalogOutputSignal(BlockState p_51928_) {
return true;
}
@Override
protected int getAnalogOutputSignal(BlockState p_51945_, Level p_51946_, BlockPos p_51947_) {
return p_51945_.getValue(LEVEL);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_51965_) {
p_51965_.add(LEVEL);
}
@Override
protected boolean isPathfindable(BlockState p_51940_, PathComputationType p_51943_) {
return false;
}
@Override
public WorldlyContainer getContainer(BlockState p_51956_, LevelAccessor p_51957_, BlockPos p_51958_) {
int i = p_51956_.getValue(LEVEL);
if (i == 8) {
return new ComposterBlock.OutputContainer(p_51956_, p_51957_, p_51958_, new ItemStack(Items.BONE_MEAL));
} else {
return (WorldlyContainer)(i < 7 ? new ComposterBlock.InputContainer(p_51956_, p_51957_, p_51958_) : new ComposterBlock.EmptyContainer());
}
}
static class EmptyContainer extends SimpleContainer implements WorldlyContainer {
public EmptyContainer() {
super(0);
}
@Override
public int[] getSlotsForFace(Direction p_52012_) {
return new int[0];
}
@Override
public boolean canPlaceItemThroughFace(int p_52008_, ItemStack p_52009_, @Nullable Direction p_52010_) {
return false;
}
@Override
public boolean canTakeItemThroughFace(int p_52014_, ItemStack p_52015_, Direction p_52016_) {
return false;
}
}
static class InputContainer extends SimpleContainer implements WorldlyContainer {
private final BlockState state;
private final LevelAccessor level;
private final BlockPos pos;
private boolean changed;
public InputContainer(BlockState p_52022_, LevelAccessor p_52023_, BlockPos p_52024_) {
super(1);
this.state = p_52022_;
this.level = p_52023_;
this.pos = p_52024_;
}
@Override
public int getMaxStackSize() {
return 1;
}
@Override
public int[] getSlotsForFace(Direction p_52032_) {
return p_52032_ == Direction.UP ? new int[]{0} : new int[0];
}
@Override
public boolean canPlaceItemThroughFace(int p_52028_, ItemStack p_52029_, @Nullable Direction p_52030_) {
return !this.changed && p_52030_ == Direction.UP && ComposterBlock.COMPOSTABLES.containsKey(p_52029_.getItem());
}
@Override
public boolean canTakeItemThroughFace(int p_52034_, ItemStack p_52035_, Direction p_52036_) {
return false;
}
@Override
public void setChanged() {
ItemStack itemstack = this.getItem(0);
if (!itemstack.isEmpty()) {
this.changed = true;
BlockState blockstate = ComposterBlock.addItem(null, this.state, this.level, this.pos, itemstack);
this.level.levelEvent(1500, this.pos, blockstate != this.state ? 1 : 0);
this.removeItemNoUpdate(0);
}
}
}
static class OutputContainer extends SimpleContainer implements WorldlyContainer {
private final BlockState state;
private final LevelAccessor level;
private final BlockPos pos;
private boolean changed;
public OutputContainer(BlockState p_52042_, LevelAccessor p_52043_, BlockPos p_52044_, ItemStack p_52045_) {
super(p_52045_);
this.state = p_52042_;
this.level = p_52043_;
this.pos = p_52044_;
}
@Override
public int getMaxStackSize() {
return 1;
}
@Override
public int[] getSlotsForFace(Direction p_52053_) {
return p_52053_ == Direction.DOWN ? new int[]{0} : new int[0];
}
@Override
public boolean canPlaceItemThroughFace(int p_52049_, ItemStack p_52050_, @Nullable Direction p_52051_) {
return false;
}
@Override
public boolean canTakeItemThroughFace(int p_52055_, ItemStack p_52056_, Direction p_52057_) {
return !this.changed && p_52057_ == Direction.DOWN && p_52056_.is(Items.BONE_MEAL);
}
@Override
public void setChanged() {
ComposterBlock.empty(null, this.state, this.level, this.pos);
this.changed = true;
}
}
}