/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.serialization.MapCodec * it.unimi.dsi.fastutil.objects.Object2FloatMap * it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap * org.jspecify.annotations.Nullable */ 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 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.util.Util; 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.Block; 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; import org.jspecify.annotations.Nullable; public class ComposterBlock extends Block implements WorldlyContainerHolder { public static final MapCodec CODEC = ComposterBlock.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 COMPOSTABLES = new Object2FloatOpenHashMap(); private static final int HOLE_WIDTH = 12; private static final VoxelShape[] SHAPES = Util.make(() -> { VoxelShape[] shapes = Block.boxes(8, level -> Shapes.join(Shapes.block(), Block.column(12.0, Math.clamp((long)(1 + level * 2), 2, 16), 16.0), BooleanOp.ONLY_FIRST)); shapes[8] = shapes[7]; return shapes; }); public MapCodec codec() { return CODEC; } public static void bootStrap() { COMPOSTABLES.defaultReturnValue(-1.0f); float low = 0.3f; float lowMid = 0.5f; float mid = 0.65f; float midHigh = 0.85f; float high = 1.0f; ComposterBlock.add(0.3f, Items.JUNGLE_LEAVES); ComposterBlock.add(0.3f, Items.OAK_LEAVES); ComposterBlock.add(0.3f, Items.SPRUCE_LEAVES); ComposterBlock.add(0.3f, Items.DARK_OAK_LEAVES); ComposterBlock.add(0.3f, Items.PALE_OAK_LEAVES); ComposterBlock.add(0.3f, Items.ACACIA_LEAVES); ComposterBlock.add(0.3f, Items.CHERRY_LEAVES); ComposterBlock.add(0.3f, Items.BIRCH_LEAVES); ComposterBlock.add(0.3f, Items.AZALEA_LEAVES); ComposterBlock.add(0.3f, Items.MANGROVE_LEAVES); ComposterBlock.add(0.3f, Items.OAK_SAPLING); ComposterBlock.add(0.3f, Items.SPRUCE_SAPLING); ComposterBlock.add(0.3f, Items.BIRCH_SAPLING); ComposterBlock.add(0.3f, Items.JUNGLE_SAPLING); ComposterBlock.add(0.3f, Items.ACACIA_SAPLING); ComposterBlock.add(0.3f, Items.CHERRY_SAPLING); ComposterBlock.add(0.3f, Items.DARK_OAK_SAPLING); ComposterBlock.add(0.3f, Items.PALE_OAK_SAPLING); ComposterBlock.add(0.3f, Items.MANGROVE_PROPAGULE); ComposterBlock.add(0.3f, Items.BEETROOT_SEEDS); ComposterBlock.add(0.3f, Items.DRIED_KELP); ComposterBlock.add(0.3f, Items.SHORT_GRASS); ComposterBlock.add(0.3f, Items.KELP); ComposterBlock.add(0.3f, Items.MELON_SEEDS); ComposterBlock.add(0.3f, Items.PUMPKIN_SEEDS); ComposterBlock.add(0.3f, Items.SEAGRASS); ComposterBlock.add(0.3f, Items.SWEET_BERRIES); ComposterBlock.add(0.3f, Items.GLOW_BERRIES); ComposterBlock.add(0.3f, Items.WHEAT_SEEDS); ComposterBlock.add(0.3f, Items.MOSS_CARPET); ComposterBlock.add(0.3f, Items.PALE_MOSS_CARPET); ComposterBlock.add(0.3f, Items.PALE_HANGING_MOSS); ComposterBlock.add(0.3f, Items.PINK_PETALS); ComposterBlock.add(0.3f, Items.WILDFLOWERS); ComposterBlock.add(0.3f, Items.LEAF_LITTER); ComposterBlock.add(0.3f, Items.SMALL_DRIPLEAF); ComposterBlock.add(0.3f, Items.HANGING_ROOTS); ComposterBlock.add(0.3f, Items.MANGROVE_ROOTS); ComposterBlock.add(0.3f, Items.TORCHFLOWER_SEEDS); ComposterBlock.add(0.3f, Items.PITCHER_POD); ComposterBlock.add(0.3f, Items.FIREFLY_BUSH); ComposterBlock.add(0.3f, Items.BUSH); ComposterBlock.add(0.3f, Items.CACTUS_FLOWER); ComposterBlock.add(0.3f, Items.DRY_SHORT_GRASS); ComposterBlock.add(0.3f, Items.DRY_TALL_GRASS); ComposterBlock.add(0.5f, Items.DRIED_KELP_BLOCK); ComposterBlock.add(0.5f, Items.TALL_GRASS); ComposterBlock.add(0.5f, Items.FLOWERING_AZALEA_LEAVES); ComposterBlock.add(0.5f, Items.CACTUS); ComposterBlock.add(0.5f, Items.SUGAR_CANE); ComposterBlock.add(0.5f, Items.VINE); ComposterBlock.add(0.5f, Items.NETHER_SPROUTS); ComposterBlock.add(0.5f, Items.WEEPING_VINES); ComposterBlock.add(0.5f, Items.TWISTING_VINES); ComposterBlock.add(0.5f, Items.MELON_SLICE); ComposterBlock.add(0.5f, Items.GLOW_LICHEN); ComposterBlock.add(0.65f, Items.SEA_PICKLE); ComposterBlock.add(0.65f, Items.LILY_PAD); ComposterBlock.add(0.65f, Items.PUMPKIN); ComposterBlock.add(0.65f, Items.CARVED_PUMPKIN); ComposterBlock.add(0.65f, Items.MELON); ComposterBlock.add(0.65f, Items.APPLE); ComposterBlock.add(0.65f, Items.BEETROOT); ComposterBlock.add(0.65f, Items.CARROT); ComposterBlock.add(0.65f, Items.COCOA_BEANS); ComposterBlock.add(0.65f, Items.POTATO); ComposterBlock.add(0.65f, Items.WHEAT); ComposterBlock.add(0.65f, Items.BROWN_MUSHROOM); ComposterBlock.add(0.65f, Items.RED_MUSHROOM); ComposterBlock.add(0.65f, Items.MUSHROOM_STEM); ComposterBlock.add(0.65f, Items.CRIMSON_FUNGUS); ComposterBlock.add(0.65f, Items.WARPED_FUNGUS); ComposterBlock.add(0.65f, Items.NETHER_WART); ComposterBlock.add(0.65f, Items.CRIMSON_ROOTS); ComposterBlock.add(0.65f, Items.WARPED_ROOTS); ComposterBlock.add(0.65f, Items.SHROOMLIGHT); ComposterBlock.add(0.65f, Items.DANDELION); ComposterBlock.add(0.65f, Items.POPPY); ComposterBlock.add(0.65f, Items.BLUE_ORCHID); ComposterBlock.add(0.65f, Items.ALLIUM); ComposterBlock.add(0.65f, Items.AZURE_BLUET); ComposterBlock.add(0.65f, Items.RED_TULIP); ComposterBlock.add(0.65f, Items.ORANGE_TULIP); ComposterBlock.add(0.65f, Items.WHITE_TULIP); ComposterBlock.add(0.65f, Items.PINK_TULIP); ComposterBlock.add(0.65f, Items.OXEYE_DAISY); ComposterBlock.add(0.65f, Items.CORNFLOWER); ComposterBlock.add(0.65f, Items.LILY_OF_THE_VALLEY); ComposterBlock.add(0.65f, Items.WITHER_ROSE); ComposterBlock.add(0.65f, Items.OPEN_EYEBLOSSOM); ComposterBlock.add(0.65f, Items.CLOSED_EYEBLOSSOM); ComposterBlock.add(0.65f, Items.FERN); ComposterBlock.add(0.65f, Items.SUNFLOWER); ComposterBlock.add(0.65f, Items.LILAC); ComposterBlock.add(0.65f, Items.ROSE_BUSH); ComposterBlock.add(0.65f, Items.PEONY); ComposterBlock.add(0.65f, Items.LARGE_FERN); ComposterBlock.add(0.65f, Items.SPORE_BLOSSOM); ComposterBlock.add(0.65f, Items.AZALEA); ComposterBlock.add(0.65f, Items.MOSS_BLOCK); ComposterBlock.add(0.65f, Items.PALE_MOSS_BLOCK); ComposterBlock.add(0.65f, Items.BIG_DRIPLEAF); ComposterBlock.add(0.85f, Items.HAY_BLOCK); ComposterBlock.add(0.85f, Items.BROWN_MUSHROOM_BLOCK); ComposterBlock.add(0.85f, Items.RED_MUSHROOM_BLOCK); ComposterBlock.add(0.85f, Items.NETHER_WART_BLOCK); ComposterBlock.add(0.85f, Items.WARPED_WART_BLOCK); ComposterBlock.add(0.85f, Items.FLOWERING_AZALEA); ComposterBlock.add(0.85f, Items.BREAD); ComposterBlock.add(0.85f, Items.BAKED_POTATO); ComposterBlock.add(0.85f, Items.COOKIE); ComposterBlock.add(0.85f, Items.TORCHFLOWER); ComposterBlock.add(0.85f, Items.PITCHER_PLANT); ComposterBlock.add(1.0f, Items.CAKE); ComposterBlock.add(1.0f, Items.PUMPKIN_PIE); } private static void add(float value, ItemLike item) { COMPOSTABLES.put((Object)item.asItem(), value); } public ComposterBlock(BlockBehaviour.Properties properties) { super(properties); this.registerDefaultState((BlockState)((BlockState)this.stateDefinition.any()).setValue(LEVEL, 0)); } public static void handleFill(Level level, BlockPos pos, boolean success) { BlockState state = level.getBlockState(pos); level.playLocalSound(pos, success ? SoundEvents.COMPOSTER_FILL_SUCCESS : SoundEvents.COMPOSTER_FILL, SoundSource.BLOCKS, 1.0f, 1.0f, false); double centerHeight = state.getShape(level, pos).max(Direction.Axis.Y, 0.5, 0.5) + 0.03125; double sideOffsetPixels = 2.0; double sideOffset = 0.1875; double width = 0.625; RandomSource random = level.getRandom(); for (int i = 0; i < 10; ++i) { double xa = random.nextGaussian() * 0.02; double ya = random.nextGaussian() * 0.02; double za = random.nextGaussian() * 0.02; level.addParticle(ParticleTypes.COMPOSTER, (double)pos.getX() + 0.1875 + 0.625 * (double)random.nextFloat(), (double)pos.getY() + centerHeight + (double)random.nextFloat() * (1.0 - centerHeight), (double)pos.getZ() + 0.1875 + 0.625 * (double)random.nextFloat(), xa, ya, za); } } @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return SHAPES[state.getValue(LEVEL)]; } @Override protected VoxelShape getInteractionShape(BlockState state, BlockGetter level, BlockPos pos) { return Shapes.block(); } @Override protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return SHAPES[0]; } @Override protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { if (state.getValue(LEVEL) == 7) { level.scheduleTick(pos, state.getBlock(), 20); } } @Override protected InteractionResult useItemOn(ItemStack itemStack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) { int fillLevel = state.getValue(LEVEL); if (fillLevel < 8 && COMPOSTABLES.containsKey((Object)itemStack.getItem())) { if (fillLevel < 7 && !level.isClientSide()) { BlockState newState = ComposterBlock.addItem(player, state, level, pos, itemStack); level.levelEvent(1500, pos, state != newState ? 1 : 0); player.awardStat(Stats.ITEM_USED.get(itemStack.getItem())); itemStack.consume(1, player); } return InteractionResult.SUCCESS; } return super.useItemOn(itemStack, state, level, pos, player, hand, hitResult); } @Override protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { int fillLevel = state.getValue(LEVEL); if (fillLevel == 8) { ComposterBlock.extractProduce(player, state, level, pos); return InteractionResult.SUCCESS; } return InteractionResult.PASS; } public static BlockState insertItem(Entity sourceEntity, BlockState state, ServerLevel level, ItemStack itemStack, BlockPos pos) { int fillLevel = state.getValue(LEVEL); if (fillLevel < 7 && COMPOSTABLES.containsKey((Object)itemStack.getItem())) { BlockState newState = ComposterBlock.addItem(sourceEntity, state, level, pos, itemStack); itemStack.shrink(1); return newState; } return state; } public static BlockState extractProduce(Entity sourceEntity, BlockState state, Level level, BlockPos pos) { if (!level.isClientSide()) { Vec3 itemPos = Vec3.atLowerCornerWithOffset(pos, 0.5, 1.01, 0.5).offsetRandomXZ(level.random, 0.7f); ItemEntity entity = new ItemEntity(level, itemPos.x(), itemPos.y(), itemPos.z(), new ItemStack(Items.BONE_MEAL)); entity.setDefaultPickUpDelay(); level.addFreshEntity(entity); } BlockState emptyState = ComposterBlock.empty(sourceEntity, state, level, pos); level.playSound(null, pos, SoundEvents.COMPOSTER_EMPTY, SoundSource.BLOCKS, 1.0f, 1.0f); return emptyState; } private static BlockState empty(@Nullable Entity sourceEntity, BlockState state, LevelAccessor level, BlockPos pos) { BlockState newState = (BlockState)state.setValue(LEVEL, 0); level.setBlock(pos, newState, 3); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); return newState; } private static BlockState addItem(@Nullable Entity sourceEntity, BlockState state, LevelAccessor level, BlockPos pos, ItemStack itemStack) { int fillLevel = state.getValue(LEVEL); float chance = COMPOSTABLES.getFloat((Object)itemStack.getItem()); if (fillLevel == 0 && chance > 0.0f || level.getRandom().nextDouble() < (double)chance) { int newLevel = fillLevel + 1; BlockState newState = (BlockState)state.setValue(LEVEL, newLevel); level.setBlock(pos, newState, 3); level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); if (newLevel == 7) { level.scheduleTick(pos, state.getBlock(), 20); } return newState; } return state; } @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (state.getValue(LEVEL) == 7) { level.setBlock(pos, (BlockState)state.cycle(LEVEL), 3); level.playSound(null, pos, SoundEvents.COMPOSTER_READY, SoundSource.BLOCKS, 1.0f, 1.0f); } } @Override protected boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos, Direction direction) { return state.getValue(LEVEL); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(LEVEL); } @Override protected boolean isPathfindable(BlockState state, PathComputationType type) { return false; } @Override public WorldlyContainer getContainer(BlockState state, LevelAccessor level, BlockPos pos) { int contentLevel = state.getValue(LEVEL); if (contentLevel == 8) { return new OutputContainer(state, level, pos, new ItemStack(Items.BONE_MEAL)); } if (contentLevel < 7) { return new InputContainer(state, level, pos); } return new EmptyContainer(); } private 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 state, LevelAccessor level, BlockPos pos, ItemStack contents) { super(contents); this.state = state; this.level = level; this.pos = pos; } @Override public int getMaxStackSize() { return 1; } @Override public int[] getSlotsForFace(Direction direction) { int[] nArray; if (direction == Direction.DOWN) { int[] nArray2 = new int[1]; nArray = nArray2; nArray2[0] = 0; } else { nArray = new int[]{}; } return nArray; } @Override public boolean canPlaceItemThroughFace(int slot, ItemStack itemStack, @Nullable Direction direction) { return false; } @Override public boolean canTakeItemThroughFace(int slot, ItemStack itemStack, Direction direction) { return !this.changed && direction == Direction.DOWN && itemStack.is(Items.BONE_MEAL); } @Override public void setChanged() { ComposterBlock.empty(null, this.state, this.level, this.pos); this.changed = true; } } private 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 state, LevelAccessor level, BlockPos pos) { super(1); this.state = state; this.level = level; this.pos = pos; } @Override public int getMaxStackSize() { return 1; } @Override public int[] getSlotsForFace(Direction direction) { int[] nArray; if (direction == Direction.UP) { int[] nArray2 = new int[1]; nArray = nArray2; nArray2[0] = 0; } else { nArray = new int[]{}; } return nArray; } @Override public boolean canPlaceItemThroughFace(int slot, ItemStack itemStack, @Nullable Direction direction) { return !this.changed && direction == Direction.UP && COMPOSTABLES.containsKey((Object)itemStack.getItem()); } @Override public boolean canTakeItemThroughFace(int slot, ItemStack itemStack, Direction direction) { return false; } @Override public void setChanged() { ItemStack contents = this.getItem(0); if (!contents.isEmpty()) { this.changed = true; BlockState newState = ComposterBlock.addItem(null, this.state, this.level, this.pos, contents); this.level.levelEvent(1500, this.pos, newState != this.state ? 1 : 0); this.removeItemNoUpdate(0); } } } private static class EmptyContainer extends SimpleContainer implements WorldlyContainer { public EmptyContainer() { super(0); } @Override public int[] getSlotsForFace(Direction direction) { return new int[0]; } @Override public boolean canPlaceItemThroughFace(int slot, ItemStack itemStack, @Nullable Direction direction) { return false; } @Override public boolean canTakeItemThroughFace(int slot, ItemStack itemStack, Direction direction) { return false; } } }