This commit is contained in:
GaLicn 2025-09-06 15:00:31 +08:00
parent f0a22ece19
commit a5a3d340c1
6 changed files with 116 additions and 109 deletions

View File

@ -189,8 +189,9 @@ sourceSets.main.java {
include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java' include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java'
include 'com/extendedae_plus/NewIcon.java' include 'com/extendedae_plus/NewIcon.java'
// Note: Curios 宿/ ae2wtlib API // Curios wtlib API
// include 'com/extendedae_plus/menu/locator/CuriosItemLocator.java' include 'com/extendedae_plus/menu/locator/CuriosItemLocator.java'
// 宿
// include 'com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java' // include 'com/extendedae_plus/menu/host/CuriosWirelessTerminalMenuHost.java'
// include 'com/extendedae_plus/menu/host/CuriosWTMenuHost.java' // include 'com/extendedae_plus/menu/host/CuriosWTMenuHost.java'
} }

View File

@ -1,57 +1,21 @@
package com.extendedae_plus.menu.host; package com.extendedae_plus.menu.host;
import appeng.menu.ISubMenu; 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.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 适配器 * 基于 ae2wtlib API 的最小封装
* - 复用 wtlib 的量子卡跨维/跨距逻辑rangeCheck/isQuantumLinked * 直接复用 wtlib WTMenuHost 构造不再自定义回写逻辑
* - 覆写槽位校验与回写改为使用 Curios 实际槽位避免 wtlib Trinkets 平台判断失效 * AE2 ItemMenuHostLocator Curios 槽位就地更新物品
*/ */
public class CuriosWTMenuHost extends WTMenuHost { public class CuriosWTMenuHost extends WTMenuHost {
private final ICurioStacksHandler curiosHandler; public CuriosWTMenuHost(ItemWT item,
private final int curiosIndex; Player player,
ItemMenuHostLocator locator,
public CuriosWTMenuHost(Player player, java.util.function.BiConsumer<Player, ISubMenu> returnToMainMenu) {
@Nullable Integer inventorySlot, super(item, player, locator, returnToMainMenu);
ItemStack is,
ICurioStacksHandler curiosHandler,
int curiosIndex,
BiConsumer<Player, ISubMenu> 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);
} }
} }

View File

@ -1,40 +1,34 @@
package com.extendedae_plus.menu.host; package com.extendedae_plus.menu.host;
import appeng.api.storage.ISubMenuHost;
import appeng.helpers.WirelessTerminalMenuHost; import appeng.helpers.WirelessTerminalMenuHost;
import appeng.menu.ISubMenu; 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.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import com.extendedae_plus.menu.locator.CuriosItemLocator;
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
/** /**
* 针对 Curios 槽位的无线终端菜单宿主 * 针对 Curios 槽位的无线终端菜单宿主
* 关键点 onBroadcastChanges 周期性把 getItemStack() 回写到 Curios 槽位 * 通过传入 CuriosItemLocator AE2 ItemMenuHost Curios 槽位上就地修改 ItemStack
* 以持久化能量消耗等 NBT 变化
*/ */
public class CuriosWirelessTerminalMenuHost extends WirelessTerminalMenuHost implements ISubMenuHost { public class CuriosWirelessTerminalMenuHost extends WirelessTerminalMenuHost<WirelessTerminalItem> {
private final ICurioStacksHandler curiosHandler; private final ICurioStacksHandler curiosHandler;
private final int curiosIndex; private final int curiosIndex;
private final String curiosSlotId;
public CuriosWirelessTerminalMenuHost(Player player, public CuriosWirelessTerminalMenuHost(Player player,
String curiosSlotId,
ItemStack itemStack, ItemStack itemStack,
ICurioStacksHandler curiosHandler, ICurioStacksHandler curiosHandler,
int curiosIndex, int curiosIndex,
java.util.function.BiConsumer<Player, ISubMenu> returnToMainMenu) { java.util.function.BiConsumer<Player, ISubMenu> returnToMainMenu) {
super(player, null, itemStack, returnToMainMenu); super((WirelessTerminalItem) itemStack.getItem(), player,
(ItemMenuHostLocator) new CuriosItemLocator(curiosSlotId, curiosIndex),
returnToMainMenu);
this.curiosHandler = curiosHandler; this.curiosHandler = curiosHandler;
this.curiosIndex = curiosIndex; this.curiosIndex = curiosIndex;
} this.curiosSlotId = curiosSlotId;
@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);
} }
} }

View File

@ -2,49 +2,44 @@ package com.extendedae_plus.menu.locator;
import appeng.api.implementations.menuobjects.IMenuItem; import appeng.api.implementations.menuobjects.IMenuItem;
import appeng.api.implementations.menuobjects.ItemMenuHost; import appeng.api.implementations.menuobjects.ItemMenuHost;
import appeng.helpers.WirelessTerminalMenuHost;
import appeng.items.tools.powered.WirelessTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.menu.MenuOpener; import appeng.menu.MenuOpener;
import appeng.menu.locator.MenuHostLocator; import appeng.menu.locator.ItemMenuHostLocator;
import appeng.menu.me.common.MEStorageMenu; import appeng.menu.me.common.MEStorageMenu;
import com.extendedae_plus.menu.host.CuriosWTMenuHost; import de.mari_023.ae2wtlib.api.registration.WTDefinition;
import com.extendedae_plus.menu.host.CuriosWirelessTerminalMenuHost; import de.mari_023.ae2wtlib.api.terminal.WTMenuHost;
import de.mari_023.ae2wtlib.terminal.WTMenuHost;
import de.mari_023.ae2wtlib.wut.WTDefinition;
import de.mari_023.ae2wtlib.wut.WUTHandler;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.CuriosApi;
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
/** /**
* 适配 Curios 槽位的自定义 MenuLocator * 适配 Curios 槽位的自定义 MenuLocator
* 通过 slotId + index 在两端查找 Curios 实际物品引用确保 NBT 变化如耗电能持久化 * 通过 slotId + index 在两端查找 Curios 实际物品引用确保 NBT 变化如耗电能持久化
*/ */
public record CuriosItemLocator(String slotId, int index) implements MenuHostLocator { public record CuriosItemLocator(String slotId, int index) implements ItemMenuHostLocator {
@Override @Override
@Nullable @Nullable
public <T> T locate(Player player, Class<T> hostInterface) { public <T> T locate(Player player, Class<T> hostInterface) {
try { try {
var resolved = CuriosApi.getCuriosInventory(player).resolve(); var opt = CuriosApi.getCuriosInventory(player);
if (resolved.isPresent()) { if (opt.isPresent()) {
var handler = resolved.get(); var handler = opt.get();
ICurioStacksHandler stacksHandler = handler.getCurios().get(slotId); ICurioStacksHandler stacksHandler = handler.getCurios().get(slotId);
if (stacksHandler != null) { if (stacksHandler != null) {
ItemStack it = stacksHandler.getStacks().getStackInSlot(index); ItemStack it = stacksHandler.getStacks().getStackInSlot(index);
if (!it.isEmpty()) { if (!it.isEmpty()) {
// 1) ae2wtlib: 优先构造 WTMenuHost 以启用量子卡的跨维/跨距逻辑 // 1) ae2wtlib: 优先通过 WTDefinition 工厂创建 WTMenuHost支持量子桥逻辑
String current = WUTHandler.getCurrentTerminal(it); WTDefinition def = WTDefinition.ofOrNull(it);
WTDefinition def = WUTHandler.wirelessTerminals.get(current);
if (def != null) { if (def != null) {
WTMenuHost wtHost = new CuriosWTMenuHost( WTMenuHost wtHost = def.wTMenuHostFactory().create(
def.item(),
player, player,
null, this,
it,
stacksHandler,
index,
(p, sub) -> MenuOpener.open(MEStorageMenu.WIRELESS_TYPE, p, this) (p, sub) -> MenuOpener.open(MEStorageMenu.WIRELESS_TYPE, p, this)
); );
if (hostInterface.isInstance(wtHost)) { 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) { if (it.getItem() instanceof WirelessTerminalItem) {
// 首选 CraftAmountMenu 等需要网络/能量上下文的菜单提供 WirelessTerminalMenuHost // IMenuItem 提供菜单宿主定位器传入当前 CuriosItemLocator
WirelessTerminalMenuHost host = new CuriosWirelessTerminalMenuHost( if (it.getItem() instanceof IMenuItem guiItem) {
player, ItemMenuHost menuHost = guiItem.getMenuHost(player, this, null);
it, if (hostInterface.isInstance(menuHost)) {
stacksHandler, return hostInterface.cast(menuHost);
index, }
(p, sub) -> MenuOpener.open(MEStorageMenu.WIRELESS_TYPE, p, this)
);
if (hostInterface.isInstance(host)) {
return hostInterface.cast(host);
} }
} else if (it.getItem() instanceof IMenuItem guiItem) { } else if (it.getItem() instanceof IMenuItem guiItem) {
// 回退非无线终端按常规 IMenuItem 处理 // 回退非无线终端按常规 IMenuItem 处理
ItemMenuHost menuHost = guiItem.getMenuHost(player, -1, it, null); ItemMenuHost menuHost = guiItem.getMenuHost(player, this, null);
if (hostInterface.isInstance(menuHost)) { if (hostInterface.isInstance(menuHost)) {
return hostInterface.cast(menuHost); return hostInterface.cast(menuHost);
} }
@ -80,6 +71,27 @@ public record CuriosItemLocator(String slotId, int index) implements MenuHostLoc
return null; 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) { public void writeToPacket(FriendlyByteBuf buf) {
buf.writeUtf(slotId); buf.writeUtf(slotId);
buf.writeVarInt(index); buf.writeVarInt(index);

View File

@ -6,6 +6,7 @@ import appeng.api.stacks.GenericStack;
import appeng.items.tools.powered.WirelessTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.menu.locator.MenuLocators; import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftAmountMenu; import appeng.menu.me.crafting.CraftAmountMenu;
import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
@ -49,7 +50,14 @@ public class OpenCraftFromJeiC2SPacket implements CustomPacketPayload {
var located = WirelessTerminalLocator.find(player); var located = WirelessTerminalLocator.find(player);
if (located.isEmpty()) return; 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主手/副手/背包仍按原先流程做前置校验保持行为一致 // Curios主手/副手/背包仍按原先流程做前置校验保持行为一致
if (!(located.stack.getItem() instanceof WirelessTerminalItem wt)) return; if (!(located.stack.getItem() instanceof WirelessTerminalItem wt)) return;

View File

@ -8,8 +8,11 @@ import appeng.api.storage.StorageHelper;
import appeng.items.tools.powered.WirelessCraftingTerminalItem; import appeng.items.tools.powered.WirelessCraftingTerminalItem;
import appeng.items.tools.powered.WirelessTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.me.helpers.PlayerSource; import appeng.me.helpers.PlayerSource;
import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.WirelessTerminalLocator;
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
@ -73,13 +76,36 @@ public class PickFromWirelessC2SPacket implements CustomPacketPayload {
if (terminal.isEmpty()) return; if (terminal.isEmpty()) return;
IGrid grid; IGrid grid;
// 统一走 AE2 原生路径处理包含 Curios 情况 boolean usedWtHost = false;
WirelessCraftingTerminalItem wct = terminal.getItem() instanceof WirelessCraftingTerminalItem c ? c : null; String curiosSlotId = located.getCuriosSlotId();
WirelessTerminalItem wt = wct != null ? wct : (terminal.getItem() instanceof WirelessTerminalItem t ? t : null); int curiosIndex = located.getCuriosIndex();
if (wt == null) return; if (curiosSlotId != null && curiosIndex >= 0) {
grid = wt.getLinkedGrid(terminal, level, null); WTDefinition def = WTDefinition.ofOrNull(terminal);
if (grid == null) return; if (def != null) {
if (!wt.hasPower(player, 0.5, terminal)) return; 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 对应的物品使用客户端实际命中位置保证多部件方块能返回正确克隆物品 // 计算 pick 对应的物品使用客户端实际命中位置保证多部件方块能返回正确克隆物品
BlockHitResult bhr = new BlockHitResult(msg.hitLoc, msg.face, msg.pos, true); 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)); inv.setItem(free, targetKey.toStack((int) extracted));
} }
WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null; if (!usedWtHost) {
WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null); WirelessCraftingTerminalItem wct2 = terminal.getItem() instanceof WirelessCraftingTerminalItem c2 ? c2 : null;
if (wt2 != null) { WirelessTerminalItem wt2 = wct2 != null ? wct2 : (terminal.getItem() instanceof WirelessTerminalItem t2 ? t2 : null);
wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal); if (wt2 != null) {
wt2.usePower(player, Math.max(0.5, extracted * 0.05), terminal);
}
} }
located.commit(); located.commit();
player.containerMenu.broadcastChanges(); player.containerMenu.broadcastChanges();