/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.serialization.MapCodec * org.jspecify.annotations.Nullable */ package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import java.util.List; import java.util.Map; import java.util.OptionalInt; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; import net.minecraft.util.RandomSource; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SelectableSlotContainer; import net.minecraft.world.level.block.SideChainPartBlock; import net.minecraft.world.level.block.SimpleWaterloggedBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.ShelfBlockEntity; 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.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.SideChainPart; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.BlockHitResult; 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 ShelfBlock extends BaseEntityBlock implements SelectableSlotContainer, SideChainPartBlock, SimpleWaterloggedBlock { public static final MapCodec CODEC = ShelfBlock.simpleCodec(ShelfBlock::new); public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public static final EnumProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final EnumProperty SIDE_CHAIN_PART = BlockStateProperties.SIDE_CHAIN_PART; public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; private static final Map SHAPES = Shapes.rotateHorizontal(Shapes.or(Block.box(0.0, 12.0, 11.0, 16.0, 16.0, 13.0), Block.box(0.0, 0.0, 13.0, 16.0, 16.0, 16.0), Block.box(0.0, 0.0, 11.0, 16.0, 4.0, 13.0))); public MapCodec codec() { return CODEC; } public ShelfBlock(BlockBehaviour.Properties properties) { super(properties); this.registerDefaultState((BlockState)((BlockState)((BlockState)((BlockState)((BlockState)this.stateDefinition.any()).setValue(FACING, Direction.NORTH)).setValue(POWERED, false)).setValue(SIDE_CHAIN_PART, SideChainPart.UNCONNECTED)).setValue(WATERLOGGED, false)); } @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return SHAPES.get(state.getValue(FACING)); } @Override protected boolean useShapeForLightOcclusion(BlockState state) { return true; } @Override protected boolean isPathfindable(BlockState state, PathComputationType type) { return type == PathComputationType.WATER && state.getFluidState().is(FluidTags.WATER); } @Override public @Nullable BlockEntity newBlockEntity(BlockPos worldPosition, BlockState blockState) { return new ShelfBlockEntity(worldPosition, blockState); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(FACING, POWERED, SIDE_CHAIN_PART, WATERLOGGED); } @Override protected void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) { Containers.updateNeighboursAfterDestroy(state, level, pos); this.updateNeighborsAfterPoweringDown(level, pos, state); } @Override protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, @Nullable Orientation orientation, boolean movedByPiston) { if (level.isClientSide()) { return; } boolean signal = level.hasNeighborSignal(pos); if (state.getValue(POWERED) != signal) { BlockState newState = (BlockState)state.setValue(POWERED, signal); if (!signal) { newState = (BlockState)newState.setValue(SIDE_CHAIN_PART, SideChainPart.UNCONNECTED); } level.setBlock(pos, newState, 3); this.playSound(level, pos, signal ? SoundEvents.SHELF_ACTIVATE : SoundEvents.SHELF_DEACTIVATE); level.gameEvent(signal ? GameEvent.BLOCK_ACTIVATE : GameEvent.BLOCK_DEACTIVATE, pos, GameEvent.Context.of(newState)); } } @Override public BlockState getStateForPlacement(BlockPlaceContext context) { FluidState replacedFluidState = context.getLevel().getFluidState(context.getClickedPos()); return (BlockState)((BlockState)((BlockState)this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite())).setValue(POWERED, context.getLevel().hasNeighborSignal(context.getClickedPos()))).setValue(WATERLOGGED, replacedFluidState.getType() == Fluids.WATER); } @Override public BlockState rotate(BlockState state, Rotation rotation) { return (BlockState)state.setValue(FACING, rotation.rotate(state.getValue(FACING))); } @Override public BlockState mirror(BlockState state, Mirror mirror) { return state.rotate(mirror.getRotation(state.getValue(FACING))); } @Override public int getRows() { return 1; } @Override public int getColumns() { return 3; } @Override protected InteractionResult useItemOn(ItemStack itemStack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) { ShelfBlockEntity shelfBlockEntity; block13: { block12: { BlockEntity blockEntity = level.getBlockEntity(pos); if (!(blockEntity instanceof ShelfBlockEntity)) break block12; shelfBlockEntity = (ShelfBlockEntity)blockEntity; if (!hand.equals((Object)InteractionHand.OFF_HAND)) break block13; } return InteractionResult.PASS; } OptionalInt hitSlot = this.getHitSlot(hitResult, state.getValue(FACING)); if (hitSlot.isEmpty()) { return InteractionResult.PASS; } Inventory inventory = player.getInventory(); if (level.isClientSide()) { return inventory.getSelectedItem().isEmpty() ? InteractionResult.PASS : InteractionResult.SUCCESS; } if (!state.getValue(POWERED).booleanValue()) { boolean itemRemoved = ShelfBlock.swapSingleItem(itemStack, player, shelfBlockEntity, hitSlot.getAsInt(), inventory); if (itemRemoved) { this.playSound(level, pos, itemStack.isEmpty() ? SoundEvents.SHELF_TAKE_ITEM : SoundEvents.SHELF_SINGLE_SWAP); } else if (!itemStack.isEmpty()) { this.playSound(level, pos, SoundEvents.SHELF_PLACE_ITEM); } else { return InteractionResult.PASS; } return InteractionResult.SUCCESS.heldItemTransformedTo(itemStack); } ItemStack previousItem = inventory.getSelectedItem(); boolean anySwapped = this.swapHotbar(level, pos, inventory); if (!anySwapped) { return InteractionResult.CONSUME; } this.playSound(level, pos, SoundEvents.SHELF_MULTI_SWAP); if (previousItem == inventory.getSelectedItem()) { return InteractionResult.SUCCESS; } return InteractionResult.SUCCESS.heldItemTransformedTo(inventory.getSelectedItem()); } private static boolean swapSingleItem(ItemStack itemStack, Player player, ShelfBlockEntity shelfBlockEntity, int hitSlot, Inventory inventory) { ItemStack removedItem = shelfBlockEntity.swapItemNoUpdate(hitSlot, itemStack); ItemStack newInventoryItem = player.hasInfiniteMaterials() && removedItem.isEmpty() ? itemStack.copy() : removedItem; inventory.setItem(inventory.getSelectedSlot(), newInventoryItem); inventory.setChanged(); shelfBlockEntity.setChanged(GameEvent.ITEM_INTERACT_FINISH); return !removedItem.isEmpty(); } private boolean swapHotbar(Level level, BlockPos pos, Inventory inventory) { List connectedBlocks = this.getAllBlocksConnectedTo(level, pos); if (connectedBlocks.isEmpty()) { return false; } boolean anySwapped = false; for (int shelfPartIndex = 0; shelfPartIndex < connectedBlocks.size(); ++shelfPartIndex) { ShelfBlockEntity shelfPart = (ShelfBlockEntity)level.getBlockEntity(connectedBlocks.get(shelfPartIndex)); if (shelfPart == null) continue; for (int slot = 0; slot < shelfPart.getContainerSize(); ++slot) { int inventorySlot = 9 - (connectedBlocks.size() - shelfPartIndex) * shelfPart.getContainerSize() + slot; if (inventorySlot < 0 || inventorySlot > inventory.getContainerSize()) continue; ItemStack placedInventoryItem = inventory.removeItemNoUpdate(inventorySlot); ItemStack removedShelfItem = shelfPart.swapItemNoUpdate(slot, placedInventoryItem); if (placedInventoryItem.isEmpty() && removedShelfItem.isEmpty()) continue; inventory.setItem(inventorySlot, removedShelfItem); anySwapped = true; } inventory.setChanged(); shelfPart.setChanged(GameEvent.ENTITY_INTERACT); } return anySwapped; } @Override public SideChainPart getSideChainPart(BlockState state) { return state.getValue(SIDE_CHAIN_PART); } @Override public BlockState setSideChainPart(BlockState state, SideChainPart newPart) { return (BlockState)state.setValue(SIDE_CHAIN_PART, newPart); } @Override public Direction getFacing(BlockState state) { return state.getValue(FACING); } @Override public boolean isConnectable(BlockState state) { return state.is(BlockTags.WOODEN_SHELVES) && state.hasProperty(POWERED) && state.getValue(POWERED) != false; } @Override public int getMaxChainLength() { return 3; } @Override protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { if (state.getValue(POWERED).booleanValue()) { this.updateSelfAndNeighborsOnPoweringUp(level, pos, state, oldState); } else { this.updateNeighborsAfterPoweringDown(level, pos, state); } } private void playSound(LevelAccessor level, BlockPos pos, SoundEvent sound) { level.playSound(null, pos, sound, SoundSource.BLOCKS, 1.0f, 1.0f); } @Override protected FluidState getFluidState(BlockState state) { if (state.getValue(WATERLOGGED).booleanValue()) { return Fluids.WATER.getSource(false); } return super.getFluidState(state); } @Override protected BlockState updateShape(BlockState state, LevelReader level, ScheduledTickAccess ticks, BlockPos pos, Direction directionToNeighbour, BlockPos neighbourPos, BlockState neighbourState, RandomSource random) { if (state.getValue(WATERLOGGED).booleanValue()) { ticks.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level)); } return super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); } @Override protected boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos, Direction direction) { if (level.isClientSide()) { return 0; } if (direction != state.getValue(FACING).getOpposite()) { return 0; } BlockEntity blockEntity = level.getBlockEntity(pos); if (blockEntity instanceof ShelfBlockEntity) { ShelfBlockEntity blockEntity2 = (ShelfBlockEntity)blockEntity; int item1Bit = blockEntity2.getItem(0).isEmpty() ? 0 : 1; int item2Bit = blockEntity2.getItem(1).isEmpty() ? 0 : 1; int item3Bit = blockEntity2.getItem(2).isEmpty() ? 0 : 1; return item1Bit | item2Bit << 1 | item3Bit << 2; } return 0; } }