From a5a3d340c14ac46d680885bfcf201ce8ded06112 Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Sat, 6 Sep 2025 15:00:31 +0800 Subject: [PATCH] =?UTF-8?q?menu=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +- .../menu/host/CuriosWTMenuHost.java | 58 +++------------ .../host/CuriosWirelessTerminalMenuHost.java | 28 +++---- .../menu/locator/CuriosItemLocator.java | 74 +++++++++++-------- .../network/OpenCraftFromJeiC2SPacket.java | 10 ++- .../network/PickFromWirelessC2SPacket.java | 50 ++++++++++--- 6 files changed, 116 insertions(+), 109 deletions(-) diff --git a/build.gradle b/build.gradle index 0b3d580..8c4ec2e 100644 --- a/build.gradle +++ b/build.gradle @@ -189,8 +189,9 @@ sourceSets.main.java { include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java' include 'com/extendedae_plus/NewIcon.java' - // Note: 暂时不编译 Curios 专用宿主/定位器(依赖 ae2wtlib API 的签名差异未完成适配) - // include 'com/extendedae_plus/menu/locator/CuriosItemLocator.java' + // 重新启用已适配的 Curios 定位器(基于 wtlib API 包) + include 'com/extendedae_plus/menu/locator/CuriosItemLocator.java' + // 仍然暂不编译自定义宿主,等待完全适配后再启用 // include 'com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java' // include 'com/extendedae_plus/menu/host/CuriosWTMenuHost.java' } diff --git a/src/main/java/com/extendedae_plus/menu/host/CuriosWTMenuHost.java b/src/main/java/com/extendedae_plus/menu/host/CuriosWTMenuHost.java index febf797..e12d219 100644 --- a/src/main/java/com/extendedae_plus/menu/host/CuriosWTMenuHost.java +++ b/src/main/java/com/extendedae_plus/menu/host/CuriosWTMenuHost.java @@ -1,57 +1,21 @@ package com.extendedae_plus.menu.host; import appeng.menu.ISubMenu; -import de.mari_023.ae2wtlib.terminal.WTMenuHost; +import appeng.menu.locator.ItemMenuHostLocator; +import de.mari_023.ae2wtlib.api.terminal.ItemWT; +import de.mari_023.ae2wtlib.api.terminal.WTMenuHost; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.Nullable; -import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; - -import java.util.function.BiConsumer; /** - * 针对 Curios 槽位的 ae2wtlib WTMenuHost 适配器: - * - 复用 wtlib 的量子卡跨维/跨距逻辑(rangeCheck/isQuantumLinked)。 - * - 覆写槽位校验与回写,改为使用 Curios 实际槽位,避免 wtlib 的 Trinkets 平台判断失效。 + * 基于 ae2wtlib API 的最小封装: + * 直接复用 wtlib 的 WTMenuHost 构造,不再自定义回写逻辑, + * 由 AE2 的 ItemMenuHostLocator 在 Curios 槽位就地更新物品。 */ public class CuriosWTMenuHost extends WTMenuHost { - private final ICurioStacksHandler curiosHandler; - private final int curiosIndex; - - public CuriosWTMenuHost(Player player, - @Nullable Integer inventorySlot, - ItemStack is, - ICurioStacksHandler curiosHandler, - int curiosIndex, - BiConsumer returnToMainMenu) { - super(player, inventorySlot, is, returnToMainMenu); - this.curiosHandler = curiosHandler; - this.curiosIndex = curiosIndex; - // 初始化内部库存(含奇点槽),以便量子桥判定能够读取到频率等 NBT - try { - super.readFromNbt(); - } catch (Throwable ignored) { - } - } - - @Override - protected boolean ensureItemStillInSlot() { - try { - ItemStack cur = curiosHandler.getStacks().getStackInSlot(curiosIndex); - return !cur.isEmpty(); - } catch (Throwable ignored) { - return false; - } - } - - @Override - public boolean onBroadcastChanges(AbstractContainerMenu menu) { - try { - ItemStack current = getItemStack(); - curiosHandler.getStacks().setStackInSlot(curiosIndex, current); - } catch (Throwable ignored) { - } - return super.onBroadcastChanges(menu); + public CuriosWTMenuHost(ItemWT item, + Player player, + ItemMenuHostLocator locator, + java.util.function.BiConsumer returnToMainMenu) { + super(item, player, locator, returnToMainMenu); } } diff --git a/src/main/java/com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java b/src/main/java/com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java index caf31e9..9d5b43a 100644 --- a/src/main/java/com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java +++ b/src/main/java/com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java @@ -1,40 +1,34 @@ package com.extendedae_plus.menu.host; -import appeng.api.storage.ISubMenuHost; import appeng.helpers.WirelessTerminalMenuHost; import appeng.menu.ISubMenu; +import appeng.items.tools.powered.WirelessTerminalItem; +import appeng.menu.locator.ItemMenuHostLocator; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; +import com.extendedae_plus.menu.locator.CuriosItemLocator; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; /** * 针对 Curios 槽位的无线终端菜单宿主。 - * 关键点:在 onBroadcastChanges 周期性把 getItemStack() 回写到 Curios 槽位, - * 以持久化能量消耗等 NBT 变化。 + * 通过传入 CuriosItemLocator 让 AE2 的 ItemMenuHost 在 Curios 槽位上就地修改 ItemStack。 */ -public class CuriosWirelessTerminalMenuHost extends WirelessTerminalMenuHost implements ISubMenuHost { +public class CuriosWirelessTerminalMenuHost extends WirelessTerminalMenuHost { private final ICurioStacksHandler curiosHandler; private final int curiosIndex; + private final String curiosSlotId; public CuriosWirelessTerminalMenuHost(Player player, + String curiosSlotId, ItemStack itemStack, ICurioStacksHandler curiosHandler, int curiosIndex, java.util.function.BiConsumer returnToMainMenu) { - super(player, null, itemStack, returnToMainMenu); + super((WirelessTerminalItem) itemStack.getItem(), player, + (ItemMenuHostLocator) new CuriosItemLocator(curiosSlotId, curiosIndex), + returnToMainMenu); this.curiosHandler = curiosHandler; this.curiosIndex = curiosIndex; - } - - @Override - public boolean onBroadcastChanges(AbstractContainerMenu menu) { - // 将当前 ItemStack 写回 Curios 槽位,保证 NBT 改动(如耗电)持久化 - try { - ItemStack current = getItemStack(); - curiosHandler.getStacks().setStackInSlot(curiosIndex, current); - } catch (Throwable ignored) { - } - return super.onBroadcastChanges(menu); + this.curiosSlotId = curiosSlotId; } } diff --git a/src/main/java/com/extendedae_plus/menu/locator/CuriosItemLocator.java b/src/main/java/com/extendedae_plus/menu/locator/CuriosItemLocator.java index f0902c6..4a9f296 100644 --- a/src/main/java/com/extendedae_plus/menu/locator/CuriosItemLocator.java +++ b/src/main/java/com/extendedae_plus/menu/locator/CuriosItemLocator.java @@ -2,49 +2,44 @@ package com.extendedae_plus.menu.locator; import appeng.api.implementations.menuobjects.IMenuItem; import appeng.api.implementations.menuobjects.ItemMenuHost; -import appeng.helpers.WirelessTerminalMenuHost; import appeng.items.tools.powered.WirelessTerminalItem; import appeng.menu.MenuOpener; -import appeng.menu.locator.MenuHostLocator; +import appeng.menu.locator.ItemMenuHostLocator; import appeng.menu.me.common.MEStorageMenu; -import com.extendedae_plus.menu.host.CuriosWTMenuHost; -import com.extendedae_plus.menu.host.CuriosWirelessTerminalMenuHost; -import de.mari_023.ae2wtlib.terminal.WTMenuHost; -import de.mari_023.ae2wtlib.wut.WTDefinition; -import de.mari_023.ae2wtlib.wut.WUTHandler; +import de.mari_023.ae2wtlib.api.registration.WTDefinition; +import de.mari_023.ae2wtlib.api.terminal.WTMenuHost; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; import org.jetbrains.annotations.Nullable; import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; /** * 适配 Curios 槽位的自定义 MenuLocator: * 通过 slotId + index 在两端查找 Curios 实际物品引用,确保 NBT 变化(如耗电)能持久化。 */ -public record CuriosItemLocator(String slotId, int index) implements MenuHostLocator { +public record CuriosItemLocator(String slotId, int index) implements ItemMenuHostLocator { @Override @Nullable public T locate(Player player, Class hostInterface) { try { - var resolved = CuriosApi.getCuriosInventory(player).resolve(); - if (resolved.isPresent()) { - var handler = resolved.get(); + var opt = CuriosApi.getCuriosInventory(player); + if (opt.isPresent()) { + var handler = opt.get(); ICurioStacksHandler stacksHandler = handler.getCurios().get(slotId); if (stacksHandler != null) { ItemStack it = stacksHandler.getStacks().getStackInSlot(index); if (!it.isEmpty()) { - // 1) ae2wtlib: 优先构造 WTMenuHost 以启用量子卡的跨维/跨距逻辑 - String current = WUTHandler.getCurrentTerminal(it); - WTDefinition def = WUTHandler.wirelessTerminals.get(current); + // 1) ae2wtlib: 优先通过 WTDefinition 工厂创建 WTMenuHost(支持量子桥逻辑) + WTDefinition def = WTDefinition.ofOrNull(it); if (def != null) { - WTMenuHost wtHost = new CuriosWTMenuHost( + WTMenuHost wtHost = def.wTMenuHostFactory().create( + def.item(), player, - null, - it, - stacksHandler, - index, + this, (p, sub) -> MenuOpener.open(MEStorageMenu.WIRELESS_TYPE, p, this) ); if (hostInterface.isInstance(wtHost)) { @@ -52,22 +47,18 @@ public record CuriosItemLocator(String slotId, int index) implements MenuHostLoc } } - // 2) 回退:AE2 原生无线终端 + // 2) 回退:AE2 原生无线终端(IMenuItem) if (it.getItem() instanceof WirelessTerminalItem) { - // 首选:为 CraftAmountMenu 等需要网络/能量上下文的菜单提供 WirelessTerminalMenuHost - WirelessTerminalMenuHost host = new CuriosWirelessTerminalMenuHost( - player, - it, - stacksHandler, - index, - (p, sub) -> MenuOpener.open(MEStorageMenu.WIRELESS_TYPE, p, this) - ); - if (hostInterface.isInstance(host)) { - return hostInterface.cast(host); + // 由 IMenuItem 提供菜单宿主,定位器传入当前 CuriosItemLocator + if (it.getItem() instanceof IMenuItem guiItem) { + ItemMenuHost menuHost = guiItem.getMenuHost(player, this, null); + if (hostInterface.isInstance(menuHost)) { + return hostInterface.cast(menuHost); + } } } else if (it.getItem() instanceof IMenuItem guiItem) { // 回退:非无线终端,按常规 IMenuItem 处理 - ItemMenuHost menuHost = guiItem.getMenuHost(player, -1, it, null); + ItemMenuHost menuHost = guiItem.getMenuHost(player, this, null); if (hostInterface.isInstance(menuHost)) { return hostInterface.cast(menuHost); } @@ -80,6 +71,27 @@ public record CuriosItemLocator(String slotId, int index) implements MenuHostLoc return null; } + @Override + public ItemStack locateItem(Player player) { + try { + var opt = CuriosApi.getCuriosInventory(player); + if (opt.isPresent()) { + ICuriosItemHandler handler = opt.get(); + ICurioStacksHandler stacksHandler = handler.getCurios().get(slotId); + if (stacksHandler != null) { + return stacksHandler.getStacks().getStackInSlot(index); + } + } + } catch (Throwable ignored) { + } + return ItemStack.EMPTY; + } + + @Override + public @Nullable BlockHitResult hitResult() { + return null; + } + public void writeToPacket(FriendlyByteBuf buf) { buf.writeUtf(slotId); buf.writeVarInt(index); diff --git a/src/main/java/com/extendedae_plus/network/OpenCraftFromJeiC2SPacket.java b/src/main/java/com/extendedae_plus/network/OpenCraftFromJeiC2SPacket.java index 0104e87..13999c1 100644 --- a/src/main/java/com/extendedae_plus/network/OpenCraftFromJeiC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/OpenCraftFromJeiC2SPacket.java @@ -6,6 +6,7 @@ import appeng.api.stacks.GenericStack; import appeng.items.tools.powered.WirelessTerminalItem; import appeng.menu.locator.MenuLocators; import appeng.menu.me.crafting.CraftAmountMenu; +import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.util.WirelessTerminalLocator; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -49,7 +50,14 @@ public class OpenCraftFromJeiC2SPacket implements CustomPacketPayload { var located = WirelessTerminalLocator.find(player); if (located.isEmpty()) return; - // Curios 槽位暂不直接作为菜单宿主处理;仅处理原版手持/背包场景。 + // 若为 Curios 槽位:直接用 CuriosItemLocator 作为宿主打开数量界面 + String curiosSlotId = located.getCuriosSlotId(); + int curiosIndex = located.getCuriosIndex(); + if (curiosSlotId != null && curiosIndex >= 0) { + int initial = 1; + CraftAmountMenu.open(player, new CuriosItemLocator(curiosSlotId, curiosIndex), what, initial); + return; + } // 非 Curios(主手/副手/背包)仍按原先流程做前置校验,保持行为一致。 if (!(located.stack.getItem() instanceof WirelessTerminalItem wt)) return; diff --git a/src/main/java/com/extendedae_plus/network/PickFromWirelessC2SPacket.java b/src/main/java/com/extendedae_plus/network/PickFromWirelessC2SPacket.java index 5c0a52e..6087fd4 100644 --- a/src/main/java/com/extendedae_plus/network/PickFromWirelessC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/PickFromWirelessC2SPacket.java @@ -8,8 +8,11 @@ import appeng.api.storage.StorageHelper; import appeng.items.tools.powered.WirelessCraftingTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem; import appeng.me.helpers.PlayerSource; +import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; +import de.mari_023.ae2wtlib.api.registration.WTDefinition; +import de.mari_023.ae2wtlib.api.terminal.WTMenuHost; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.RegistryFriendlyByteBuf; @@ -73,13 +76,36 @@ public class PickFromWirelessC2SPacket implements CustomPacketPayload { if (terminal.isEmpty()) return; IGrid grid; - // 统一走 AE2 原生路径处理(包含 Curios 情况): - WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null; - WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null); - if (wt == null) return; - grid = wt.getLinkedGrid(terminal, level, null); - if (grid == null) return; - if (!wt.hasPower(player, 0.5, terminal)) return; + boolean usedWtHost = false; + String curiosSlotId = located.getCuriosSlotId(); + int curiosIndex = located.getCuriosIndex(); + if (curiosSlotId != null && curiosIndex >= 0) { + WTDefinition def = WTDefinition.ofOrNull(terminal); + if (def != null) { + WTMenuHost wtHost = def.wTMenuHostFactory().create( + def.item(), + player, + new CuriosItemLocator(curiosSlotId, curiosIndex), + (p, sub) -> {} + ); + if (wtHost != null && wtHost.getActionableNode() != null && wtHost.getActionableNode().getGrid() != null) { + grid = wtHost.getActionableNode().getGrid(); + usedWtHost = true; + } else { + return; + } + } else { + return; + } + } else { + // AE2 原生路径 + WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null; + WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null); + if (wt == null) return; + grid = wt.getLinkedGrid(terminal, level, null); + if (grid == null) return; + if (!wt.hasPower(player, 0.5, terminal)) return; + } // 计算 pick 对应的物品:使用客户端实际命中位置,保证多部件方块能返回正确克隆物品 BlockHitResult bhr = new BlockHitResult(msg.hitLoc, msg.face, msg.pos, true); @@ -134,10 +160,12 @@ public class PickFromWirelessC2SPacket implements CustomPacketPayload { inv.setItem(free, targetKey.toStack((int) extracted)); } - WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null; - WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null); - if (wt2 != null) { - wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal); + if (!usedWtHost) { + WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null; + WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null); + if (wt2 != null) { + wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal); + } } located.commit(); player.containerMenu.broadcastChanges();