package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import java.util.List; import java.util.Optional; import java.util.OptionalInt; import javax.annotation.Nullable; 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.stats.Stats; import net.minecraft.tags.ItemTags; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity; 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.Property; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; public class ChiseledBookShelfBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(ChiseledBookShelfBlock::new); private static final int MAX_BOOKS_IN_STORAGE = 6; public static final int BOOKS_PER_ROW = 3; public static final List SLOT_OCCUPIED_PROPERTIES = List.of( BlockStateProperties.CHISELED_BOOKSHELF_SLOT_0_OCCUPIED, BlockStateProperties.CHISELED_BOOKSHELF_SLOT_1_OCCUPIED, BlockStateProperties.CHISELED_BOOKSHELF_SLOT_2_OCCUPIED, BlockStateProperties.CHISELED_BOOKSHELF_SLOT_3_OCCUPIED, BlockStateProperties.CHISELED_BOOKSHELF_SLOT_4_OCCUPIED, BlockStateProperties.CHISELED_BOOKSHELF_SLOT_5_OCCUPIED ); @Override public MapCodec codec() { return CODEC; } public ChiseledBookShelfBlock(BlockBehaviour.Properties p_249989_) { super(p_249989_); BlockState blockstate = this.stateDefinition.any().setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH); for (BooleanProperty booleanproperty : SLOT_OCCUPIED_PROPERTIES) { blockstate = blockstate.setValue(booleanproperty, false); } this.registerDefaultState(blockstate); } @Override protected InteractionResult useItemOn( ItemStack p_336113_, BlockState p_329797_, Level p_331003_, BlockPos p_335104_, Player p_334454_, InteractionHand p_336011_, BlockHitResult p_329086_ ) { if (p_331003_.getBlockEntity(p_335104_) instanceof ChiseledBookShelfBlockEntity chiseledbookshelfblockentity) { if (!p_336113_.is(ItemTags.BOOKSHELF_BOOKS)) { return InteractionResult.TRY_WITH_EMPTY_HAND; } else { OptionalInt optionalint = this.getHitSlot(p_329086_, p_329797_); if (optionalint.isEmpty()) { return InteractionResult.PASS; } else if (p_329797_.getValue(SLOT_OCCUPIED_PROPERTIES.get(optionalint.getAsInt()))) { return InteractionResult.TRY_WITH_EMPTY_HAND; } else { addBook(p_331003_, p_335104_, p_334454_, chiseledbookshelfblockentity, p_336113_, optionalint.getAsInt()); return InteractionResult.SUCCESS; } } } else { return InteractionResult.PASS; } } @Override protected InteractionResult useWithoutItem(BlockState p_335003_, Level p_333933_, BlockPos p_333604_, Player p_334275_, BlockHitResult p_334482_) { if (p_333933_.getBlockEntity(p_333604_) instanceof ChiseledBookShelfBlockEntity chiseledbookshelfblockentity) { OptionalInt optionalint = this.getHitSlot(p_334482_, p_335003_); if (optionalint.isEmpty()) { return InteractionResult.PASS; } else if (!p_335003_.getValue(SLOT_OCCUPIED_PROPERTIES.get(optionalint.getAsInt()))) { return InteractionResult.CONSUME; } else { removeBook(p_333933_, p_333604_, p_334275_, chiseledbookshelfblockentity, optionalint.getAsInt()); return InteractionResult.SUCCESS; } } else { return InteractionResult.PASS; } } private OptionalInt getHitSlot(BlockHitResult p_333742_, BlockState p_330398_) { return getRelativeHitCoordinatesForBlockFace(p_333742_, p_330398_.getValue(HorizontalDirectionalBlock.FACING)).map(p_327255_ -> { int i = p_327255_.y >= 0.5F ? 0 : 1; int j = getSection(p_327255_.x); return OptionalInt.of(j + i * 3); }).orElseGet(OptionalInt::empty); } private static Optional getRelativeHitCoordinatesForBlockFace(BlockHitResult p_261714_, Direction p_262116_) { Direction direction = p_261714_.getDirection(); if (p_262116_ != direction) { return Optional.empty(); } else { BlockPos blockpos = p_261714_.getBlockPos().relative(direction); Vec3 vec3 = p_261714_.getLocation().subtract(blockpos.getX(), blockpos.getY(), blockpos.getZ()); double d0 = vec3.x(); double d1 = vec3.y(); double d2 = vec3.z(); return switch (direction) { case NORTH -> Optional.of(new Vec2((float)(1.0 - d0), (float)d1)); case SOUTH -> Optional.of(new Vec2((float)d0, (float)d1)); case WEST -> Optional.of(new Vec2((float)d2, (float)d1)); case EAST -> Optional.of(new Vec2((float)(1.0 - d2), (float)d1)); case DOWN, UP -> Optional.empty(); }; } } private static int getSection(float p_261599_) { float f = 0.0625F; float f1 = 0.375F; if (p_261599_ < 0.375F) { return 0; } else { float f2 = 0.6875F; return p_261599_ < 0.6875F ? 1 : 2; } } private static void addBook( Level p_262592_, BlockPos p_262669_, Player p_262572_, ChiseledBookShelfBlockEntity p_262606_, ItemStack p_262587_, int p_262692_ ) { if (!p_262592_.isClientSide) { p_262572_.awardStat(Stats.ITEM_USED.get(p_262587_.getItem())); SoundEvent soundevent = p_262587_.is(Items.ENCHANTED_BOOK) ? SoundEvents.CHISELED_BOOKSHELF_INSERT_ENCHANTED : SoundEvents.CHISELED_BOOKSHELF_INSERT; p_262606_.setItem(p_262692_, p_262587_.consumeAndReturn(1, p_262572_)); p_262592_.playSound(null, p_262669_, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F); } } private static void removeBook(Level p_262654_, BlockPos p_262601_, Player p_262636_, ChiseledBookShelfBlockEntity p_262605_, int p_262673_) { if (!p_262654_.isClientSide) { ItemStack itemstack = p_262605_.removeItem(p_262673_, 1); SoundEvent soundevent = itemstack.is(Items.ENCHANTED_BOOK) ? SoundEvents.CHISELED_BOOKSHELF_PICKUP_ENCHANTED : SoundEvents.CHISELED_BOOKSHELF_PICKUP; p_262654_.playSound(null, p_262601_, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F); if (!p_262636_.getInventory().add(itemstack)) { p_262636_.drop(itemstack, false); } p_262654_.gameEvent(p_262636_, GameEvent.BLOCK_CHANGE, p_262601_); } } @Nullable @Override public BlockEntity newBlockEntity(BlockPos p_250440_, BlockState p_248729_) { return new ChiseledBookShelfBlockEntity(p_250440_, p_248729_); } @Override protected void createBlockStateDefinition(StateDefinition.Builder p_250973_) { p_250973_.add(HorizontalDirectionalBlock.FACING); SLOT_OCCUPIED_PROPERTIES.forEach(p_261456_ -> p_250973_.add(p_261456_)); } @Override protected void affectNeighborsAfterRemoval(BlockState p_394831_, ServerLevel p_397362_, BlockPos p_395293_, boolean p_394170_) { Containers.updateNeighboursAfterDestroy(p_394831_, p_397362_, p_395293_); } @Override public BlockState getStateForPlacement(BlockPlaceContext p_251318_) { return this.defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, p_251318_.getHorizontalDirection().getOpposite()); } @Override public BlockState rotate(BlockState p_288975_, Rotation p_288993_) { return p_288975_.setValue(HorizontalDirectionalBlock.FACING, p_288993_.rotate(p_288975_.getValue(HorizontalDirectionalBlock.FACING))); } @Override public BlockState mirror(BlockState p_289000_, Mirror p_288962_) { return p_289000_.rotate(p_288962_.getRotation(p_289000_.getValue(HorizontalDirectionalBlock.FACING))); } @Override protected boolean hasAnalogOutputSignal(BlockState p_249302_) { return true; } @Override protected int getAnalogOutputSignal(BlockState p_249192_, Level p_252207_, BlockPos p_248999_) { if (p_252207_.isClientSide()) { return 0; } else { return p_252207_.getBlockEntity(p_248999_) instanceof ChiseledBookShelfBlockEntity chiseledbookshelfblockentity ? chiseledbookshelfblockentity.getLastInteractedSlot() + 1 : 0; } } }