[全流程完成]
This commit is contained in:
@@ -0,0 +1,216 @@
|
|||||||
|
package thaumicenergistics.common.container;
|
||||||
|
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import appeng.api.config.Actionable;
|
||||||
|
import appeng.api.networking.energy.IEnergySource;
|
||||||
|
import appeng.api.networking.security.IActionSource;
|
||||||
|
import appeng.api.stacks.AEKey;
|
||||||
|
import appeng.api.storage.MEStorage;
|
||||||
|
import appeng.api.storage.StorageHelper;
|
||||||
|
|
||||||
|
import thaumcraft.api.aspects.Aspect;
|
||||||
|
import thaumcraft.api.aspects.AspectList;
|
||||||
|
import thaumcraft.api.aspects.IEssentiaContainerItem;
|
||||||
|
import thaumcraft.common.items.JarBlockItem;
|
||||||
|
import thaumicenergistics.common.integration.appeng.AEssentiaKey;
|
||||||
|
import thaumicenergistics.common.integration.tc.TCReflection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源质容器 ↔ ME 网络通用存取逻辑(服务端)。
|
||||||
|
* <p>
|
||||||
|
* 与具体菜单解耦:调用方(源质终端覆写、或 ME 终端 mixin)只需提供
|
||||||
|
* storage / energySource / actionSource / player / 物品栈,本类完成
|
||||||
|
* 罐子与安瓿的装罐、存入网络操作。
|
||||||
|
* <ul>
|
||||||
|
* <li>取出(装罐):网络有源质 → 装入手持空罐(有多少装多少,最多 64)/ 空安瓿(固定 8)。</li>
|
||||||
|
* <li>存入:手持/点击的罐子或安瓿 → 源质注入网络;罐子留空罐,安瓿返回空 glass_phial(不消失)。</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public final class EssentiaFillHelper {
|
||||||
|
|
||||||
|
private EssentiaFillHelper() {}
|
||||||
|
|
||||||
|
/** 玻璃安瓿固定容量(TC 原版:8 源质/支)。 */
|
||||||
|
public static final int PHIAL_CAPACITY = 8;
|
||||||
|
/** 罐子容量(TC 原版:64 源质/罐)。 */
|
||||||
|
public static final int JAR_CAPACITY = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右键网络源质条目装罐:从网络提取源质,装入手持的源质罐子或玻璃安瓿。
|
||||||
|
*
|
||||||
|
* @return true = 处理成功(装罐/装安瓿),false = 无法处理
|
||||||
|
*/
|
||||||
|
public static boolean fillContainerFromGrid(MEStorage storage, IEnergySource energySource,
|
||||||
|
IActionSource actionSource, Player player,
|
||||||
|
ItemStack carried, ResourceLocation aspectId) {
|
||||||
|
if (carried.isEmpty() || aspectId == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AEKey key = AEssentiaKey.of(aspectId);
|
||||||
|
if (key == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long amountInGrid = storage.getAvailableStacks().get(key);
|
||||||
|
if (amountInGrid <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 玻璃安瓿:消耗空安瓿 → 得到装满安瓿(固定 8 源质)
|
||||||
|
if (carried.getItem() == BuiltInRegistries.ITEM.get(
|
||||||
|
ResourceLocation.fromNamespaceAndPath("thaumcraft", "glass_phial"))) {
|
||||||
|
if (amountInGrid < PHIAL_CAPACITY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long extracted = storage.extract(key, PHIAL_CAPACITY, Actionable.MODULATE, actionSource);
|
||||||
|
if (extracted < PHIAL_CAPACITY) {
|
||||||
|
if (extracted > 0) {
|
||||||
|
storage.insert(key, extracted, Actionable.MODULATE, actionSource);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
carried.shrink(1);
|
||||||
|
// 得到装满安瓿并放入背包(装好后自动放入背包)
|
||||||
|
ItemStack filled = filledPhialStack(aspectId.getPath());
|
||||||
|
if (!player.getInventory().add(filled)) {
|
||||||
|
player.drop(filled, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 罐子(IEssentiaContainerItem):每次只装 1 个空罐(手堆叠 -1,背包得 1 满罐)
|
||||||
|
if (!(carried.getItem() instanceof IEssentiaContainerItem container)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AspectList existing = container.getAspects(carried);
|
||||||
|
if (existing != null && !existing.isEmpty()) {
|
||||||
|
return false; // 罐子非空,不能装
|
||||||
|
}
|
||||||
|
// 部分取出:网络有多少装多少(最多 JAR_CAPACITY 64);不足 64 也能装,不再整组拒绝
|
||||||
|
long toExtract = Math.min(amountInGrid, JAR_CAPACITY);
|
||||||
|
long extracted = storage.extract(key, toExtract, Actionable.MODULATE, actionSource);
|
||||||
|
if (extracted <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Aspect aspect = Aspect.getAspect(aspectId.getPath());
|
||||||
|
if (aspect == null) {
|
||||||
|
storage.insert(key, extracted, Actionable.MODULATE, actionSource);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 生成 1 个满罐:必须先 copy(在 shrink 之前),因为 count==1 的堆叠 shrink 后
|
||||||
|
// 会变成空堆叠,ItemStack.copy() 对空堆叠直接返回全局 EMPTY 单例,setCount(1)
|
||||||
|
// 会污染该常量产生"空气幽灵堆叠",罐子因此消失。copyWithCount(1) 生成独立副本,
|
||||||
|
// setAspects 只影响这一个,不影响原堆叠。
|
||||||
|
ItemStack filledJar = carried.copyWithCount(1);
|
||||||
|
// 手堆叠 -1
|
||||||
|
carried.shrink(1);
|
||||||
|
AspectList newAspects = new AspectList();
|
||||||
|
newAspects.add(aspect, (int) extracted);
|
||||||
|
container.setAspects(filledJar, newAspects);
|
||||||
|
if (!player.getInventory().add(filledJar)) {
|
||||||
|
player.drop(filledJar, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把源质容器物品中的源质注入 ME 原生存储,返回处理后的物品栈。
|
||||||
|
* 堆叠中每个容器的源质相同(NBT 共享),按"单个量 × 堆叠数"一次注入;
|
||||||
|
* 全部注入成功才消耗容器,否则保留原堆叠,避免源质凭空消失。
|
||||||
|
* <p>
|
||||||
|
* 罐子抽干后留空罐(可重复使用);安瓿抽干后返回空 glass_phial(不消失)。
|
||||||
|
*
|
||||||
|
* @return null = 非源质容器(未处理,调用方应走原逻辑);
|
||||||
|
* 原 stack = 未注入(网络满/能量不足)或部分处理保留;
|
||||||
|
* 空罐 = 罐子全部抽干(可重复使用);
|
||||||
|
* glass_phial 空安瓿 = 安瓿全部抽干(返回空安瓿,不再消耗掉)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ItemStack extractContainerContent(MEStorage storage, IEnergySource energySource,
|
||||||
|
IActionSource actionSource, ItemStack stack) {
|
||||||
|
if (!(stack.getItem() instanceof IEssentiaContainerItem container)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int count = stack.getCount();
|
||||||
|
if (count <= 0) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
AspectList aspects = container.getAspects(stack);
|
||||||
|
if (aspects == null || aspects.isEmpty()) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阶段1:预检(SIMULATE 无副作用)——网络必须能完整容纳全部源质才继续;
|
||||||
|
// 任一项放不下则整个堆叠原样保留,避免"部分注入后罐子被消耗、剩余源质凭空消失"。
|
||||||
|
Aspect[] aspectArr = aspects.getAspects();
|
||||||
|
ResourceLocation[] ids = new ResourceLocation[aspectArr.length];
|
||||||
|
long[] totals = new long[aspectArr.length];
|
||||||
|
int n = 0;
|
||||||
|
for (Aspect aspect : aspectArr) {
|
||||||
|
if (aspect == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int perItem = aspects.getAmount(aspect);
|
||||||
|
if (perItem <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ResourceLocation aspectId = TCReflection.getAspectId(aspect);
|
||||||
|
if (aspectId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long total = (long) perItem * count;
|
||||||
|
if (storage.insert(AEssentiaKey.of(aspectId), total,
|
||||||
|
Actionable.SIMULATE, actionSource) < total) {
|
||||||
|
return stack; // 网络容量不足:完全不注入,罐子/安瓿原样保留
|
||||||
|
}
|
||||||
|
ids[n] = aspectId;
|
||||||
|
totals[n] = total;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阶段2:执行注入(预检已保证容量;若能量不足导致未完全注入,则回滚本次及此前
|
||||||
|
// 已注入的量并保留罐子,保证网络数量与罐子状态一致——不丢源质也不复制源质)
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
long injected = StorageHelper.poweredInsert(
|
||||||
|
energySource, storage, AEssentiaKey.of(ids[i]), totals[i], actionSource);
|
||||||
|
if (injected < totals[i]) {
|
||||||
|
if (injected > 0) {
|
||||||
|
storage.insert(AEssentiaKey.of(ids[i]), injected,
|
||||||
|
Actionable.MODULATE, actionSource);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
storage.insert(AEssentiaKey.of(ids[j]), totals[j],
|
||||||
|
Actionable.MODULATE, actionSource);
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全部注入成功则消耗整个堆叠(罐子留空罐、安瓿返回空 glass_phial)
|
||||||
|
if (stack.getItem() instanceof JarBlockItem) {
|
||||||
|
return new ItemStack(stack.getItem());
|
||||||
|
}
|
||||||
|
// 安瓿:返回空安瓿(glass_phial),不直接消失
|
||||||
|
ItemStack emptyPhial = new ItemStack(BuiltInRegistries.ITEM.get(
|
||||||
|
ResourceLocation.fromNamespaceAndPath("thaumcraft", "glass_phial")), count);
|
||||||
|
return emptyPhial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生成装满的安瓿(phial_of_essentia_<tag>),与 TC JarBlock.filledPhialStack 一致。 */
|
||||||
|
private static ItemStack filledPhialStack(String aspectTag) {
|
||||||
|
ResourceLocation id = ResourceLocation.fromNamespaceAndPath(
|
||||||
|
"thaumcraft", "phial_of_essentia_" + aspectTag);
|
||||||
|
net.minecraft.world.item.Item item = BuiltInRegistries.ITEM.getOptional(id)
|
||||||
|
.orElse(BuiltInRegistries.ITEM.get(
|
||||||
|
ResourceLocation.fromNamespaceAndPath("thaumcraft", "glass_phial")));
|
||||||
|
return new ItemStack(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package thaumicenergistics.common.container;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import appeng.api.storage.ITerminalHost;
|
||||||
|
import appeng.menu.me.common.MEStorageMenu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源质终端的菜单(有线端与无线端共用)。
|
||||||
|
* <p>
|
||||||
|
* 继承 AE2 原版 {@link MEStorageMenu} 的全部普通物品行为(左键/Shift+点击/拖拽均按普通物品处理)。
|
||||||
|
* 源质的存入与取出统一由右键交互承担:
|
||||||
|
* <ul>
|
||||||
|
* <li>手持装有源质的罐子/安瓿 + 右键任意处 → 源质存入网络({@link EssentiaFillHelper#extractContainerContent})。</li>
|
||||||
|
* <li>手持空罐/空安瓿 + 右键源质条目 → 从网络取出装罐({@link #fillContainerFromGrid})。</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class EssentiaTerminalMenu extends MEStorageMenu {
|
||||||
|
|
||||||
|
public EssentiaTerminalMenu(MenuType<?> menuType, int id, Inventory ip, ITerminalHost host) {
|
||||||
|
super(menuType, id, ip, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 右键终端源质条目装罐:从网络提取源质,装入手持的源质罐子或玻璃安瓿。
|
||||||
|
* 具体逻辑见 {@link EssentiaFillHelper#fillContainerFromGrid}。
|
||||||
|
*
|
||||||
|
* @param aspectId 源质 aspect 的 ResourceLocation
|
||||||
|
* @return true = 处理成功(装罐/装安瓿),false = 无法处理
|
||||||
|
*/
|
||||||
|
public boolean fillContainerFromGrid(ResourceLocation aspectId) {
|
||||||
|
if (isClientSide()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var player = getPlayerInventory().player;
|
||||||
|
var carried = getCarried();
|
||||||
|
return EssentiaFillHelper.fillContainerFromGrid(
|
||||||
|
this.storage, this.energySource, getActionSource(), player, carried, aspectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package thaumicenergistics.common.container;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import thaumcraft.api.aspects.AspectList;
|
||||||
|
import thaumcraft.api.aspects.IEssentiaContainerItem;
|
||||||
|
|
||||||
|
import appeng.client.gui.me.common.MEStorageScreen;
|
||||||
|
import appeng.client.gui.style.ScreenStyle;
|
||||||
|
|
||||||
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
import thaumicenergistics.common.network.EssentiaTerminalDepositC2SPacket;
|
||||||
|
import thaumicenergistics.common.network.EssentiaTerminalFillC2SPacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源质终端 GUI:在 AE2 通用终端基础上扩展右键交互。
|
||||||
|
* <ul>
|
||||||
|
* <li>Shift+右键玩家背包格:格内是源质容器 → 源质存入网络(空容器留原格)。</li>
|
||||||
|
* <li>右键玩家物品栏/背包槽 → 放行(AE2 原版物品交互)。</li>
|
||||||
|
* <li>右键网络区域(源质条目或空白),手持装有源质的罐子/安瓿 → 源质存入 ME 网络(空容器回背包)。</li>
|
||||||
|
* <li>手持空罐/空安瓿 + 右键源质条目 → 从网络取出源质装罐/装安瓿。</li>
|
||||||
|
* <li>左键仍是正常物品操作(不受影响)。</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class GuiEssentiaTerminal extends MEStorageScreen<EssentiaTerminalMenu> {
|
||||||
|
|
||||||
|
public GuiEssentiaTerminal(EssentiaTerminalMenu menu, Inventory playerInventory,
|
||||||
|
Component title, ScreenStyle style) {
|
||||||
|
super(menu, playerInventory, title, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double xCoord, double yCoord, int btn) {
|
||||||
|
if (btn == 1) {
|
||||||
|
var carried = this.menu.getCarried();
|
||||||
|
boolean shiftDown = net.minecraft.client.gui.screens.inventory.AbstractContainerScreen.hasShiftDown();
|
||||||
|
// 源质物品来源:优先菜单 carried;为空时回退玩家主手物品
|
||||||
|
ItemStack sourceStack = !carried.isEmpty() ? carried
|
||||||
|
: this.menu.getPlayerInventory().player.getMainHandItem();
|
||||||
|
boolean isContainer = isSourceContainer(sourceStack);
|
||||||
|
boolean containerHasEssentia = isContainer && getContainerEssentia(sourceStack) != null;
|
||||||
|
|
||||||
|
// Shift+右键玩家物品栏/背包格:格内是源质容器 → 存入源质(空容器留原格)
|
||||||
|
if (shiftDown && this.hoveredSlot != null && this.menu.isPlayerSideSlot(this.hoveredSlot)) {
|
||||||
|
var slotStack = this.hoveredSlot.getItem();
|
||||||
|
if (slotStack.getItem() instanceof IEssentiaContainerItem) {
|
||||||
|
PacketDistributor.sendToServer(EssentiaTerminalDepositC2SPacket.fromSlot(
|
||||||
|
this.menu.containerId, this.hoveredSlot.getSlotIndex(), slotStack));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 非源质容器 → 放行(AE2 原版 Shift+右键快速移动)
|
||||||
|
return super.mouseClicked(xCoord, yCoord, btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通右键点击玩家物品栏/背包槽 → 放行(AE2 原版物品交互)
|
||||||
|
if (!shiftDown && this.hoveredSlot != null && this.menu.isPlayerSideSlot(this.hoveredSlot)) {
|
||||||
|
return super.mouseClicked(xCoord, yCoord, btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift+右键:手持源质容器(满或空)→ 拦截。满→存入源质;空→阻止被当普通物品放入网络
|
||||||
|
if (shiftDown && isContainer) {
|
||||||
|
if (containerHasEssentia) {
|
||||||
|
this.menu.setCarried(net.minecraft.world.item.ItemStack.EMPTY);
|
||||||
|
PacketDistributor.sendToServer(EssentiaTerminalDepositC2SPacket.fromClientStack(
|
||||||
|
this.menu.containerId, sourceStack));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通右键网络区域:手持满容器 → 存入源质
|
||||||
|
if (containerHasEssentia) {
|
||||||
|
this.menu.setCarried(net.minecraft.world.item.ItemStack.EMPTY);
|
||||||
|
PacketDistributor.sendToServer(EssentiaTerminalDepositC2SPacket.fromClientStack(
|
||||||
|
this.menu.containerId, sourceStack));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手持空容器:右键源质条目 → 取出装罐;右键网络其他 → 拦截(防被放入网络)
|
||||||
|
if (isContainer) {
|
||||||
|
if (this.hoveredSlot instanceof appeng.client.gui.me.common.RepoSlot repoSlot) {
|
||||||
|
var entry = repoSlot.getEntry();
|
||||||
|
if (entry != null && entry.getWhat() instanceof thaumicenergistics.common.integration.appeng.AEssentiaKey key) {
|
||||||
|
PacketDistributor.sendToServer(EssentiaTerminalFillC2SPacket.create(
|
||||||
|
this.menu.containerId, key.getId(), sourceStack));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseClicked(xCoord, yCoord, btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 源质容器:实现 IEssentiaContainerItem 的物品,或空玻璃安瓿(glass_phial 不实现该接口但可装罐)。 */
|
||||||
|
private static boolean isSourceContainer(ItemStack stack) {
|
||||||
|
if (stack.getItem() instanceof IEssentiaContainerItem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return stack.is(net.minecraft.core.registries.BuiltInRegistries.ITEM.get(
|
||||||
|
net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("thaumcraft", "glass_phial")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 若手持物品是源质容器且非空,返回其 AspectList;否则返回 null。 */
|
||||||
|
@Nullable
|
||||||
|
private static AspectList getContainerEssentia(ItemStack stack) {
|
||||||
|
if (stack.getItem() instanceof IEssentiaContainerItem container) {
|
||||||
|
AspectList aspects = container.getAspects(stack);
|
||||||
|
if (aspects != null && !aspects.isEmpty()) {
|
||||||
|
return aspects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package thaumicenergistics.common.container;
|
||||||
|
|
||||||
|
import appeng.api.networking.energy.IEnergySource;
|
||||||
|
import appeng.api.storage.MEStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由 {@code MixinMEStorageMenuAccessors} 注入到 {@code MEStorageMenu} 的访问器接口。
|
||||||
|
* <p>
|
||||||
|
* 编译期接口存在、运行期目标类实现,调用方(如网络包处理)通过
|
||||||
|
* {@code instanceof ThEEssentiaMenuAccess} 安全访问 ME 存储与能量源。
|
||||||
|
* <p>
|
||||||
|
* 注意:必须放在非 mixin 包(mixin 包 {@code thaumicenergistics.mixins.*} 的类
|
||||||
|
* 禁止被普通类直接引用)。
|
||||||
|
*/
|
||||||
|
public interface ThEEssentiaMenuAccess {
|
||||||
|
|
||||||
|
/** ME 存储(对应 MEStorageMenu.storage)。 */
|
||||||
|
MEStorage thE_getStorage();
|
||||||
|
|
||||||
|
/** 能量源(对应 MEStorageMenu.energySource)。 */
|
||||||
|
IEnergySource thE_getEnergySource();
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package thaumicenergistics.common.container.slot;
|
||||||
|
|
||||||
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.SimpleContainer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.neoforge.items.IItemHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只读展示槽:显示 IItemHandler 中真实物品,但禁止玩家/整理 mod 交互。
|
||||||
|
* 与 AE2 ClientReadOnlySlot 等效(保留 inventory 用于渲染,mayPlace/mayPickup/set/remove 空操作)。
|
||||||
|
* 用于玩家不交互的纯展示槽(装配器的预存配方槽、目标产物槽)。
|
||||||
|
*/
|
||||||
|
public class ReadOnlySlot extends Slot {
|
||||||
|
|
||||||
|
/** 假 inventory 占位:阻止整理 mod 通过 slot 的 inventory/index 交互。 */
|
||||||
|
private static final Container EMPTY_INVENTORY = new SimpleContainer(0);
|
||||||
|
|
||||||
|
private final IItemHandler handler;
|
||||||
|
private final int handlerIndex;
|
||||||
|
|
||||||
|
public ReadOnlySlot(IItemHandler handler, int index, int xPosition, int yPosition) {
|
||||||
|
super(EMPTY_INVENTORY, 0, xPosition, yPosition);
|
||||||
|
this.handler = handler;
|
||||||
|
this.handlerIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack getItem() {
|
||||||
|
// 读取真实 inventory 用于渲染显示;handlerIndex 是 handler 内索引(Slot.index 是菜单槽序号,勿用)
|
||||||
|
return handler.getStackInSlot(handlerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPlace(ItemStack stack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void set(ItemStack stack) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxStackSize() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack remove(int amount) {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPickup(Player player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user