package thaumicenergistics.common.container; import java.util.List; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.items.ItemStackHandler; import net.neoforged.neoforge.items.SlotItemHandler; import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.AspectList; import thaumcraft.api.aspects.IEssentiaContainerItem; import thaumicenergistics.common.integration.tc.TCReflection; import thaumicenergistics.common.items.ItemEssentiaCell; import thaumicenergistics.common.tiles.TileEssentiaCellWorkbench; import thaumicenergistics.init.ModMenuTypes; /** * 源质元件工作台容器:cell 槽绑定到方块实体(持久化),并提供分区编辑操作。 * 对应 1.7.10 的 {@code ContainerEssentiaCellWorkbench},分区数据存储在 cell 的 AE2 CellConfig 上。 */ public class ContainerEssentiaCellWorkbench extends AbstractContainerMenu { /** cell 槽编号。 */ public static final int SLOT_CELL = 0; /** 玩家背包起始编号(1..27 背包,28..36 热栏)。 */ private static final int PLAYER_INV_START = 1; private static final int PLAYER_INV_END = 28; private static final int HOTBAR_START = 28; private static final int HOTBAR_END = 37; private final TileEssentiaCellWorkbench workbench; /** 兜底用空库存(workbench 为 null 时)。 */ private final IItemHandler fallbackCell = new ItemStackHandler(1); public ContainerEssentiaCellWorkbench(int id, Inventory inv) { this(id, inv, (TileEssentiaCellWorkbench) null); } public ContainerEssentiaCellWorkbench(int id, Inventory inv, TileEssentiaCellWorkbench workbench) { super(ModMenuTypes.ESSENTIA_CELL_WORKBENCH.get(), id); this.workbench = workbench; IItemHandler cellHandler = workbench != null ? workbench.getCellInventory() : fallbackCell; addSlot(new SlotItemHandler(cellHandler, 0, 152, 8)); for (int r = 0; r < 3; r++) for (int c = 0; c < 9; c++) addSlot(new Slot(inv, c + r * 9 + 9, 8 + c * 18, 169 + r * 18)); for (int c = 0; c < 9; c++) addSlot(new Slot(inv, c, 8 + c * 18, 227)); } /** 客户端打开菜单用(IMenuTypeExtension 注册);workbench 为 null,分区操作走 C2S 到服务端。 */ public ContainerEssentiaCellWorkbench(int id, Inventory inv, net.minecraft.network.RegistryFriendlyByteBuf buf) { this(id, inv); } // ===== 分区操作(由 GUI / 网络调用,服务端执行) ===== public boolean hasCell() { return workbench != null && workbench.hasCell(); } public List getPartitionAspects() { if (workbench == null || !workbench.hasCell()) return List.of(); return ItemEssentiaCell.getPartitionAspects(workbench.getCell()); } public boolean addAspectToPartition(ResourceLocation aspectId) { if (workbench == null || !workbench.hasCell()) return false; boolean changed = ItemEssentiaCell.addAspectToPartition(workbench.getCell(), aspectId); if (changed) workbench.setChanged(); return changed; } public boolean removeAspectFromPartition(ResourceLocation aspectId) { if (workbench == null || !workbench.hasCell()) return false; boolean changed = ItemEssentiaCell.removeAspectFromPartition(workbench.getCell(), aspectId); if (changed) workbench.setChanged(); return changed; } public boolean replaceAspectInPartition(ResourceLocation from, ResourceLocation to) { if (workbench == null || !workbench.hasCell()) return false; boolean changed = ItemEssentiaCell.replaceAspectInPartition(workbench.getCell(), from, to); if (changed) workbench.setChanged(); return changed; } public void clearPartitioning() { if (workbench == null || !workbench.hasCell()) return; ItemEssentiaCell.clearPartitioning(workbench.getCell()); workbench.setChanged(); } public void partitionToContents() { if (workbench == null || !workbench.hasCell()) return; ItemEssentiaCell.partitionToContents(workbench.getCell()); workbench.setChanged(); } /** * 从物品中提取第一个源质方面(罐子/法杖等 IEssentiaContainerItem)。 */ public static ResourceLocation getAspectFromItem(ItemStack stack) { if (stack == null || stack.isEmpty()) return null; if (stack.getItem() instanceof IEssentiaContainerItem containerItem) { AspectList aspects = containerItem.getAspects(stack); if (aspects != null && aspects.size() > 0) { Aspect first = aspects.getAspects()[0]; if (first != null) return TCReflection.getAspectId(first); } } return null; } // ===== 快捷移动 / 生命周期 ===== @Override public ItemStack quickMoveStack(Player player, int idx) { if (workbench == null || idx < 0 || idx >= slots.size()) return ItemStack.EMPTY; Slot slot = slots.get(idx); if (!slot.hasItem()) return ItemStack.EMPTY; ItemStack stack = slot.getItem(); ItemStack original = stack.copy(); if (idx == SLOT_CELL) { // cell 槽 → 玩家背包 if (!moveItemStackTo(stack, PLAYER_INV_START, HOTBAR_END, true)) return ItemStack.EMPTY; } else if (idx < HOTBAR_END) { // 玩家背包 → cell 槽(仅当 cell 槽空且物品是源质元件) if (stack.getItem() instanceof ItemEssentiaCell && workbench.getCell().isEmpty()) { if (!moveItemStackTo(stack, SLOT_CELL, SLOT_CELL + 1, false)) return ItemStack.EMPTY; } else { // 含源质物品 → 尝试添加分区(物品不消费,仅添加分区) ResourceLocation aspectId = getAspectFromItem(stack); if (aspectId != null && addAspectToPartition(aspectId)) { return original; // 物品留在原槽 } return ItemStack.EMPTY; } } if (stack.isEmpty()) { slot.set(ItemStack.EMPTY); } else { slot.setChanged(); } return original; } @Override public boolean stillValid(Player player) { return workbench == null || workbench.hasLevel() && player.level().getBlockEntity(workbench.getBlockPos()) == workbench; } }