diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java index 7cba84b..1c93b75 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java @@ -1,5 +1,6 @@ package com.extendedae_plus.mixin.ae2.accessor; +import appeng.api.networking.IManagedGridNode; import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogicHost; import org.spongepowered.asm.mixin.Mixin; @@ -9,4 +10,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface PatternProviderLogicAccessor { @Accessor("host") PatternProviderLogicHost eap$host(); + + @Accessor("mainNode") + IManagedGridNode eap$mainNode(); } diff --git a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java index 5f984b2..f8e198f 100644 --- a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java @@ -85,31 +85,8 @@ public class CraftingMonitorOpenProviderC2SPacket { var pbe = host.getBlockEntity(); if (pbe == null) continue; - // 跳过未连接到网格或不活跃的 provider(例如缺少频道/通道) - try { - var providerGrid = ppl.getGrid(); - if (providerGrid == null || !providerGrid.equals(grid)) { - continue; - } - // 如果 provider 自身对外提供的通道/频道信息不可用或不活跃,跳过 - try { - // 尝试通过 provider 的主节点判断是否有 channel - var mainNodeField = ppl.getClass().getDeclaredField("mainNode"); - mainNodeField.setAccessible(true); - var mainNode = mainNodeField.get(ppl); - if (mainNode == null) continue; - var getChannelsMethod = mainNode.getClass().getMethod("getChannels"); - Object channels = null; - channels = getChannelsMethod.invoke(mainNode); - if (channels instanceof java.util.Collection) { - if (((java.util.Collection) channels).isEmpty()) continue; - } - } catch (Exception ignored) { - // 无法判断 channel 时继续:不因反射失败而阻止正常 provider - } - } catch (Exception e) { - continue; - } + // 跳过未连接到网格或不活跃的 provider(使用 util 判断并传入当前 grid) + if (!PatternProviderDataUtil.isProviderAvailable(ppl, grid)) continue; // 直接打开供应器自身的 UI(调用 Host 默认方法) try { @@ -121,7 +98,7 @@ public class CraftingMonitorOpenProviderC2SPacket { } // 先在该 provider 中定位 pattern 的槽位索引,以便计算页码(尽量早退出,按槽位逐个解码) - int foundSlot = findSlotIndexInProvider(ppl, pattern); + int foundSlot = PatternProviderDataUtil.findSlotForPattern(ppl, pattern.getDefinition()); if (foundSlot >= 0) { int pageId = foundSlot / 36; if (pageId > 0) { @@ -145,20 +122,4 @@ public class CraftingMonitorOpenProviderC2SPacket { }); context.setPacketHandled(true); } - - private static int findSlotIndexInProvider(PatternProviderLogic ppl, IPatternDetails pattern) { - try { - // 通过逐槽位解码并在找到匹配定义时立即返回索引,避免分配大量对象 - var list = PatternProviderDataUtil.getAllPatternData(ppl); - for (var pd : list) { - if (pd != null && pd.getPatternDetails() != null && pd.getPatternDetails().getDefinition().equals(pattern.getDefinition())) { - return pd.getSlotIndex(); - } - } - } catch (Exception ignored) { - } - return -1; - } - - } diff --git a/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java b/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java index c9285c1..9209f3e 100644 --- a/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java +++ b/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java @@ -3,13 +3,14 @@ package com.extendedae_plus.util; import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.PatternDetailsHelper; import appeng.api.inventories.InternalInventory; +import appeng.api.networking.IGrid; import appeng.api.stacks.AEKey; import appeng.api.stacks.GenericStack; import appeng.helpers.patternprovider.PatternProviderLogic; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; +import com.mojang.logging.LogUtils; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import appeng.helpers.patternprovider.PatternProviderLogicHost; import net.minecraft.world.level.block.entity.BlockEntity; import java.util.ArrayList; @@ -242,12 +243,15 @@ public class PatternProviderDataUtil { // 遍历所有样板槽位 for (int i = 0; i < patternInventory.size(); i++) { ItemStack patternStack = patternInventory.getStackInSlot(i); - if (!patternStack.isEmpty()) { + if (patternStack.isEmpty()) continue; + try { // 解码样板 IPatternDetails patternDetails = PatternDetailsHelper.decodePattern(patternStack, level); if (patternDetails != null) { patternDataList.add(new PatternData(patternDetails, patternStack, i)); } + } catch (Exception e) { + if (DEBUG) LogUtils.getLogger().debug("Pattern decode failed at slot {}: {}", i, e.toString()); } } @@ -397,6 +401,59 @@ public class PatternProviderDataUtil { return patternProvider.getGrid() != null; } + /** + * 判断 provider 是否可用并属于指定网格(在线且有频道/处于活跃状态) + */ + public static boolean isProviderAvailable(PatternProviderLogic provider, IGrid expectedGrid) { + if (provider == null || expectedGrid == null) return false; + try { + var grid = provider.getGrid(); + if (grid == null || !grid.equals(expectedGrid)) return false; + + // 使用 accessor 获取 mainNode,再调用 isActive + if (provider instanceof PatternProviderLogicAccessor accessor) { + var mainNode = accessor.eap$mainNode(); + if (mainNode == null) return false; + try { + var isActiveMethod = mainNode.getClass().getMethod("isActive"); + Object active = isActiveMethod.invoke(mainNode); + if (active instanceof Boolean && !((Boolean) active)) return false; + } catch (NoSuchMethodException nsme) { + // 没有 isActive 方法时,退回到检查 channels + try { + var getChannels = mainNode.getClass().getMethod("getChannels"); + Object channels = getChannels.invoke(mainNode); + if (channels instanceof java.util.Collection) { + if (((java.util.Collection) channels).isEmpty()) return false; + } + } catch (Exception ignored) { + // 无法判断 channels 时,认为不可用 + return false; + } + } + } else { + // 没有 accessor 的情况,尽量通过反射判断 mainNode.channels + try { + var mainNodeField = provider.getClass().getDeclaredField("mainNode"); + mainNodeField.setAccessible(true); + var mainNode = mainNodeField.get(provider); + if (mainNode == null) return false; + var getChannelsMethod = mainNode.getClass().getMethod("getChannels"); + Object channels = getChannelsMethod.invoke(mainNode); + if (channels instanceof java.util.Collection) { + return !((java.util.Collection) channels).isEmpty(); + } + } catch (Exception e) { + return false; + } + } + + return true; + } catch (Exception e) { + return false; + } + } + /** * 检查样板供应器是否处于活跃状态 * @@ -411,18 +468,21 @@ public class PatternProviderDataUtil { if (grid == null) { return false; } - // 检查网格节点是否活跃 + // 检查网格节点是否活跃(使用 accessor 代替反射) try { - // 使用反射安全地访问mainNode字段 - var mainNodeField = patternProvider.getClass().getDeclaredField("mainNode"); - mainNodeField.setAccessible(true); - var mainNode = mainNodeField.get(patternProvider); - if (mainNode != null) { - var isActiveMethod = mainNode.getClass().getMethod("isActive"); - return (Boolean) isActiveMethod.invoke(mainNode); + if (patternProvider instanceof PatternProviderLogicAccessor accessor) { + var mainNode = accessor.eap$mainNode(); + if (mainNode != null) { + try { + var isActiveMethod = mainNode.getClass().getMethod("isActive"); + return (Boolean) isActiveMethod.invoke(mainNode); + } catch (Exception e) { + // 无法调用 isActive 时,认为活跃 + return true; + } + } } - } catch (Exception e) { - // 如果反射失败,假设是活跃的 + } catch (Exception ignored) { } return true; } @@ -490,6 +550,34 @@ public class PatternProviderDataUtil { return scalePatternAmountsExtendedAEStyle(patternProvider, multiplier, true); } + /** + * 查找 provider 中匹配给定定义的样板槽位(轻量、按需解码并早退出) + * @param patternProvider 要搜索的 provider + * @param targetDefinition pattern.getDefinition() 返回的对象(用于 equals 比较) + * @return 找到的槽位索引,未找到返回 -1 + */ + public static int findSlotForPattern(PatternProviderLogic patternProvider, Object targetDefinition) { + if (patternProvider == null || targetDefinition == null) return -1; + InternalInventory inv = patternProvider.getPatternInv(); + if (inv == null) return -1; + Level level = getPatternProviderLevel(patternProvider); + if (level == null) return -1; + + for (int i = 0; i < inv.size(); i++) { + ItemStack s = inv.getStackInSlot(i); + if (s.isEmpty()) continue; + try { + IPatternDetails d = PatternDetailsHelper.decodePattern(s, level); + if (d != null && d.getDefinition().equals(targetDefinition)) { + return i; + } + } catch (Exception e) { + if (DEBUG) LogUtils.getLogger().debug("findSlotForPattern decode failed at {}: {}", i, e.toString()); + } + } + return -1; + } + /** * ExtendedAE风格的样板复制倍增 * 支持更精确的样板处理和错误恢复