package net.minecraft.world.level.block.entity; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; import net.minecraft.core.component.DataComponents; import net.minecraft.core.component.DataComponentMap.Builder; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.LockCode; import net.minecraft.world.MenuProvider; import net.minecraft.world.Nameable; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.ItemContainerContents; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; public abstract class BaseContainerBlockEntity extends BlockEntity implements Container, MenuProvider, Nameable { private LockCode lockKey = LockCode.NO_LOCK; @Nullable private Component name; protected BaseContainerBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { super(type, pos, blockState); } @Override protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { super.loadAdditional(tag, registries); this.lockKey = LockCode.fromTag(tag, registries); if (tag.contains("CustomName", 8)) { this.name = parseCustomNameSafe(tag.getString("CustomName"), registries); } } @Override protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { super.saveAdditional(tag, registries); this.lockKey.addToTag(tag, registries); if (this.name != null) { tag.putString("CustomName", Component.Serializer.toJson(this.name, registries)); } } @Override public Component getName() { return this.name != null ? this.name : this.getDefaultName(); } @Override public Component getDisplayName() { return this.getName(); } @Nullable @Override public Component getCustomName() { return this.name; } protected abstract Component getDefaultName(); public boolean canOpen(Player player) { return canUnlock(player, this.lockKey, this.getDisplayName()); } public static boolean canUnlock(Player player, LockCode code, Component displayName) { if (!player.isSpectator() && !code.unlocksWith(player.getMainHandItem())) { player.displayClientMessage(Component.translatable("container.isLocked", displayName), true); player.playNotifySound(SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); return false; } else { return true; } } protected abstract NonNullList getItems(); protected abstract void setItems(NonNullList items); @Override public boolean isEmpty() { for (ItemStack itemStack : this.getItems()) { if (!itemStack.isEmpty()) { return false; } } return true; } @Override public ItemStack getItem(int slot) { return this.getItems().get(slot); } @Override public ItemStack removeItem(int slot, int amount) { ItemStack itemStack = ContainerHelper.removeItem(this.getItems(), slot, amount); if (!itemStack.isEmpty()) { this.setChanged(); } return itemStack; } @Override public ItemStack removeItemNoUpdate(int slot) { return ContainerHelper.takeItem(this.getItems(), slot); } @Override public void setItem(int slot, ItemStack stack) { this.getItems().set(slot, stack); stack.limitSize(this.getMaxStackSize(stack)); this.setChanged(); } @Override public boolean stillValid(Player player) { return Container.stillValidBlockEntity(this, player); } @Override public void clearContent() { this.getItems().clear(); } @Nullable @Override public AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) { return this.canOpen(player) ? this.createMenu(i, inventory) : null; } protected abstract AbstractContainerMenu createMenu(int containerId, Inventory inventory); @Override protected void applyImplicitComponents(BlockEntity.DataComponentInput componentInput) { super.applyImplicitComponents(componentInput); this.name = componentInput.get(DataComponents.CUSTOM_NAME); this.lockKey = componentInput.getOrDefault(DataComponents.LOCK, LockCode.NO_LOCK); componentInput.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).copyInto(this.getItems()); } @Override protected void collectImplicitComponents(Builder components) { super.collectImplicitComponents(components); components.set(DataComponents.CUSTOM_NAME, this.name); if (!this.lockKey.equals(LockCode.NO_LOCK)) { components.set(DataComponents.LOCK, this.lockKey); } components.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(this.getItems())); } @Override public void removeComponentsFromTag(CompoundTag tag) { tag.remove("CustomName"); tag.remove("lock"); tag.remove("Items"); } }