diff --git a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java index feb3285..5f984b2 100644 --- a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java @@ -13,7 +13,6 @@ import appeng.menu.me.crafting.CraftingCPUMenu; import appeng.parts.AEBasePart; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; import com.extendedae_plus.util.PatternProviderDataUtil; -import com.mojang.logging.LogUtils; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkDirection; @@ -49,11 +48,8 @@ public class CraftingMonitorOpenProviderC2SPacket { ServerPlayer player = context.getSender(); if (player == null) return; - LogUtils.getLogger().info("EAP[S]: recv CraftingMonitorOpenProviderC2SPacket key={} from {}", msg.what, player.getGameProfile().getName()); - // 必须在 CraftingCPU 界面内 if (!(player.containerMenu instanceof CraftingCPUMenu menu)) { - LogUtils.getLogger().info("EAP[S]: not in CraftingCPUMenu, abort"); return; } @@ -64,19 +60,16 @@ public class CraftingMonitorOpenProviderC2SPacket { grid = host.getActionableNode().getGrid(); } if (grid == null) { - LogUtils.getLogger().info("EAP[S]: grid is null, abort"); return; } var cs = grid.getCraftingService(); if (!(cs instanceof CraftingService craftingService)) { - LogUtils.getLogger().info("EAP[S]: craftingService is null/unsupported, abort"); return; } // 1) 根据 AEKey 找到可能的样板(pattern) Collection patterns = craftingService.getCraftingFor(msg.what); - LogUtils.getLogger().info("EAP[S]: patterns found={} for key={}", patterns.size(), msg.what); if (patterns.isEmpty()) { return; } @@ -91,14 +84,35 @@ public class CraftingMonitorOpenProviderC2SPacket { if (host == null) continue; var pbe = host.getBlockEntity(); if (pbe == null) continue; - // 在服务端上下文中执行,pbe 仅用于构造菜单定位器 + + // 跳过未连接到网格或不活跃的 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; + } // 直接打开供应器自身的 UI(调用 Host 默认方法) try { - // 告知目标玩家客户端高亮该 AEKey(避免全局服务端状态污染) - AEKey key = pattern.getOutputs()[0].what(); - ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); - // 部件与方块实体分别选择定位器并打开界面 if (host instanceof AEBasePart part) { host.openMenu(player, MenuLocators.forPart(part)); @@ -106,18 +120,8 @@ public class CraftingMonitorOpenProviderC2SPacket { host.openMenu(player, MenuLocators.forBlockEntity(pbe)); } - // 先在该 provider 中定位 pattern 的槽位索引,以便计算页码 - int foundSlot = -1; - var list = PatternProviderDataUtil.getAllPatternData(ppl); - for (var pd : list) { - - if (pd != null && pd.getPatternDetails() != null - && pd.getPatternDetails().getDefinition().equals(pattern.getDefinition())) { - foundSlot = pd.getSlotIndex(); - break; - } - - } + // 先在该 provider 中定位 pattern 的槽位索引,以便计算页码(尽量早退出,按槽位逐个解码) + int foundSlot = findSlotIndexInProvider(ppl, pattern); if (foundSlot >= 0) { int pageId = foundSlot / 36; if (pageId > 0) { @@ -125,19 +129,36 @@ public class CraftingMonitorOpenProviderC2SPacket { ModNetwork.CHANNEL.sendTo(new SetProviderPageS2CPacket(pageId), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); } } - context.setPacketHandled(true); + + // 最后发送高亮包,保证界面已打开 + if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) { + AEKey key = pattern.getOutputs()[0].what(); + ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); + } + return; - } catch (Throwable t) { - LogUtils.getLogger().error("EAP[S]: open provider UI failed at {}", pbe.getBlockPos(), t); + } catch (Exception ignored) { } } } } - - LogUtils.getLogger().info("EAP[S]: no provider UI opened for key={}", msg.what); }); 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 15b0ad7..c9285c1 100644 --- a/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java +++ b/src/main/java/com/extendedae_plus/util/PatternProviderDataUtil.java @@ -6,8 +6,11 @@ import appeng.api.inventories.InternalInventory; import appeng.api.stacks.AEKey; import appeng.api.stacks.GenericStack; import appeng.helpers.patternprovider.PatternProviderLogic; +import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; 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; import java.util.HashMap; @@ -230,26 +233,8 @@ public class PatternProviderDataUtil { if (patternInventory == null) { return patternDataList; } - - // 通过反射安全地访问host字段获取Level - Level level = null; - try { - var hostField = patternProvider.getClass().getDeclaredField("host"); - hostField.setAccessible(true); - var host = hostField.get(patternProvider); - if (host != null) { - var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); - var blockEntity = getBlockEntityMethod.invoke(host); - if (blockEntity != null) { - var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); - level = (Level) getLevelMethod.invoke(blockEntity); - } - } - } catch (Exception e) { - // 如果反射失败,返回空列表 - return patternDataList; - } - + // 获取 Level(使用 mixin accessor 替代反射) + Level level = getPatternProviderLevel(patternProvider); if (level == null) { return patternDataList; } @@ -353,24 +338,7 @@ public class PatternProviderDataUtil { return null; } - // 通过反射安全地访问host字段获取Level - Level level = null; - try { - var hostField = patternProvider.getClass().getDeclaredField("host"); - hostField.setAccessible(true); - var host = hostField.get(patternProvider); - if (host != null) { - var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); - var blockEntity = getBlockEntityMethod.invoke(host); - if (blockEntity != null) { - var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); - level = (Level) getLevelMethod.invoke(blockEntity); - } - } - } catch (Exception e) { - return null; - } - + Level level = getPatternProviderLevel(patternProvider); if (level == null) { return null; } @@ -862,50 +830,30 @@ public class PatternProviderDataUtil { // 1. 设置物品到库存 patternInventory.setItemDirect(slot, newPattern); - // 2. 标记数据为脏数据,确保保存到磁盘 + // 2. 标记数据为脏数据,确保保存到磁盘(尝试使用 mixin accessor 替代反射) try { - // 通过反射获取host并标记为脏数据 - var hostField = patternProvider.getClass().getDeclaredField("host"); - hostField.setAccessible(true); - var host = hostField.get(patternProvider); - - if (host != null) { - // 获取BlockEntity并标记为脏数据 - var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); - var blockEntity = getBlockEntityMethod.invoke(host); - - if (blockEntity != null) { - // 调用setChanged()方法标记为脏数据 - var setChangedMethod = blockEntity.getClass().getMethod("setChanged"); - setChangedMethod.invoke(blockEntity); - - // 尝试触发网络同步 - try { - var levelField = blockEntity.getClass().getSuperclass().getDeclaredField("level"); - levelField.setAccessible(true); - Level level = (Level) levelField.get(blockEntity); - - if (level != null && !level.isClientSide()) { - // 服务器端:强制同步到客户端 - var getBlockPosMethod = blockEntity.getClass().getMethod("getBlockPos"); - var blockPos = getBlockPosMethod.invoke(blockEntity); - - if (blockPos != null) { - // 通知客户端方块状态变更 - var getBlockStateMethod = blockEntity.getClass().getMethod("getBlockState"); - var blockState = getBlockStateMethod.invoke(blockEntity); - level.sendBlockUpdated((net.minecraft.core.BlockPos) blockPos, - (net.minecraft.world.level.block.state.BlockState) blockState, - (net.minecraft.world.level.block.state.BlockState) blockState, 3); - } + if (patternProvider instanceof PatternProviderLogicAccessor accessor) { + var host = accessor.eap$host(); + if (host != null) { + BlockEntity be = host.getBlockEntity(); + if (be != null) { + try { + be.setChanged(); + } catch (Exception ignored) { + } + try { + Level level = be.getLevel(); + if (level != null && !level.isClientSide()) { + var pos = be.getBlockPos(); + var state = be.getBlockState(); + level.sendBlockUpdated(pos, state, state, 3); + } + } catch (Exception ignored) { } - } catch (Exception syncException) { - // 网络同步失败不影响主要功能 } } } - } catch (Exception e) { - // 如果反射失败,使用备用方案 + } catch (Exception ignored) { } // 3. 强制更新样板缓存 @@ -920,20 +868,18 @@ public class PatternProviderDataUtil { * ExtendedAE风格:安全获取样板供应器的Level对象 */ private static Level getPatternProviderLevel(PatternProviderLogic patternProvider) { + if (patternProvider == null) return null; try { - var hostField = patternProvider.getClass().getDeclaredField("host"); - hostField.setAccessible(true); - var host = hostField.get(patternProvider); - if (host != null) { - var getBlockEntityMethod = host.getClass().getMethod("getBlockEntity"); - var blockEntity = getBlockEntityMethod.invoke(host); - if (blockEntity != null) { - var getLevelMethod = blockEntity.getClass().getMethod("getLevel"); - return (Level) getLevelMethod.invoke(blockEntity); + if (patternProvider instanceof PatternProviderLogicAccessor accessor) { + var host = accessor.eap$host(); + if (host != null) { + BlockEntity be = host.getBlockEntity(); + if (be != null) { + return be.getLevel(); + } } } - } catch (Exception e) { - // 静默处理异常,返回null让调用者处理 + } catch (Exception ignored) { } return null; }