2025-11-24 22:52:51 +03:00

484 lines
20 KiB
Java

/*
* 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<ComposterBlock> 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<ItemLike> 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<ComposterBlock> 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<Block, BlockState> 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;
}
}
}