package net.minecraft.world.level.block.entity; import com.mojang.logging.LogUtils; import java.util.Objects; import java.util.function.Predicate; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.core.component.DataComponentGetter; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; import net.minecraft.tags.ItemTags; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.ItemContainerContents; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.ChiseledBookShelfBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import org.slf4j.Logger; public class ChiseledBookShelfBlockEntity extends BlockEntity implements Container { public static final int MAX_BOOKS_IN_STORAGE = 6; private static final Logger LOGGER = LogUtils.getLogger(); private static final int DEFAULT_LAST_INTERACTED_SLOT = -1; private final NonNullList items = NonNullList.withSize(6, ItemStack.EMPTY); private int lastInteractedSlot = -1; public ChiseledBookShelfBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.CHISELED_BOOKSHELF, pos, state); } private void updateState(int slot) { if (slot >= 0 && slot < 6) { this.lastInteractedSlot = slot; BlockState blockState = this.getBlockState(); for (int i = 0; i < ChiseledBookShelfBlock.SLOT_OCCUPIED_PROPERTIES.size(); i++) { boolean bl = !this.getItem(i).isEmpty(); BooleanProperty booleanProperty = (BooleanProperty)ChiseledBookShelfBlock.SLOT_OCCUPIED_PROPERTIES.get(i); blockState = blockState.setValue(booleanProperty, bl); } ((Level)Objects.requireNonNull(this.level)).setBlock(this.worldPosition, blockState, 3); this.level.gameEvent(GameEvent.BLOCK_CHANGE, this.worldPosition, GameEvent.Context.of(blockState)); } else { LOGGER.error("Expected slot 0-5, got {}", slot); } } @Override protected void loadAdditional(ValueInput input) { super.loadAdditional(input); this.items.clear(); ContainerHelper.loadAllItems(input, this.items); this.lastInteractedSlot = input.getIntOr("last_interacted_slot", -1); } @Override protected void saveAdditional(ValueOutput output) { super.saveAdditional(output); ContainerHelper.saveAllItems(output, this.items, true); output.putInt("last_interacted_slot", this.lastInteractedSlot); } public int count() { return (int)this.items.stream().filter(Predicate.not(ItemStack::isEmpty)).count(); } @Override public void clearContent() { this.items.clear(); } @Override public int getContainerSize() { return 6; } @Override public boolean isEmpty() { return this.items.stream().allMatch(ItemStack::isEmpty); } @Override public ItemStack getItem(int slot) { return this.items.get(slot); } @Override public ItemStack removeItem(int slot, int amount) { ItemStack itemStack = (ItemStack)Objects.requireNonNullElse(this.items.get(slot), ItemStack.EMPTY); this.items.set(slot, ItemStack.EMPTY); if (!itemStack.isEmpty()) { this.updateState(slot); } return itemStack; } @Override public ItemStack removeItemNoUpdate(int slot) { return this.removeItem(slot, 1); } @Override public void setItem(int slot, ItemStack stack) { if (stack.is(ItemTags.BOOKSHELF_BOOKS)) { this.items.set(slot, stack); this.updateState(slot); } else if (stack.isEmpty()) { this.removeItem(slot, 1); } } @Override public boolean canTakeItem(Container target, int slot, ItemStack stack) { return target.hasAnyMatching( itemStack2 -> itemStack2.isEmpty() ? true : ItemStack.isSameItemSameComponents(stack, itemStack2) && itemStack2.getCount() + stack.getCount() <= target.getMaxStackSize(itemStack2) ); } @Override public int getMaxStackSize() { return 1; } @Override public boolean stillValid(Player player) { return Container.stillValidBlockEntity(this, player); } @Override public boolean canPlaceItem(int slot, ItemStack stack) { return stack.is(ItemTags.BOOKSHELF_BOOKS) && this.getItem(slot).isEmpty() && stack.getCount() == this.getMaxStackSize(); } public int getLastInteractedSlot() { return this.lastInteractedSlot; } @Override protected void applyImplicitComponents(DataComponentGetter componentGetter) { super.applyImplicitComponents(componentGetter); componentGetter.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).copyInto(this.items); } @Override protected void collectImplicitComponents(DataComponentMap.Builder components) { super.collectImplicitComponents(components); components.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(this.items)); } @Override public void removeComponentsFromTag(ValueOutput output) { output.discard("Items"); } }