From 1d115c46e07e9dbf99d19fe6a0d1c46f44879815 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 20 Oct 2025 23:33:20 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99mixin=20plugin,=20=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E9=80=BB=E8=BE=91,=20=E5=8E=BB=E6=8E=89=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compat/UpgradeSlotCompat.java | 149 +----------------- .../mixin/MixinConditions.java | 93 ++++------- .../PatternProviderMenuUpgradesMixin.java | 61 ------- .../extendedae_plus/util/ModCheckUtils.java | 81 ++++++++++ 4 files changed, 116 insertions(+), 268 deletions(-) delete mode 100644 src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuUpgradesMixin.java create mode 100644 src/main/java/com/extendedae_plus/util/ModCheckUtils.java diff --git a/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java b/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java index c6eab7a..96382dd 100644 --- a/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java +++ b/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java @@ -1,23 +1,9 @@ package com.extendedae_plus.compat; import appeng.api.upgrades.IUpgradeInventory; -import appeng.api.upgrades.IUpgradeableObject; -import appeng.client.gui.style.ScreenStyle; -import appeng.client.gui.widgets.ToolboxPanel; -import appeng.client.gui.widgets.UpgradesPanel; -import appeng.core.localization.GuiText; -import appeng.helpers.patternprovider.PatternProviderLogicHost; -import appeng.menu.AEBaseMenu; -import appeng.menu.SlotSemantics; import appeng.menu.ToolboxMenu; -import com.extendedae_plus.util.Logger; -import net.minecraft.network.chat.Component; -import net.minecraft.world.inventory.Slot; import net.minecraftforge.fml.ModList; -import java.util.ArrayList; -import java.util.List; - /** * 升级卡槽兼容性管理类 * 检测ExtendedAE-appflux模组是否存在,如果存在则使用其升级卡槽功能 @@ -59,140 +45,7 @@ public class UpgradeSlotCompat { public static boolean shouldAddUpgradePanelToScreen() { return shouldEnableUpgradeSlots(); } - - /** - * 初始化菜单升级功能(如果需要的话) - * @param menu 目标菜单 - * @param host 样板供应器逻辑主机 - * @return 是否成功初始化 - */ - public static boolean initMenuUpgrades(AEBaseMenu menu, PatternProviderLogicHost host) { - if (!shouldEnableUpgradeSlots()) { - return false; - } - - try { - // 创建工具箱菜单 - ToolboxMenu toolbox = new ToolboxMenu(menu); - - // 设置升级槽 - if (host instanceof IUpgradeableObject upgradeableHost) { - // 使用反射调用protected的setupUpgrades方法 - try { - var setupUpgradesMethod = AEBaseMenu.class.getDeclaredMethod("setupUpgrades", IUpgradeInventory.class); - setupUpgradesMethod.setAccessible(true); - setupUpgradesMethod.invoke(menu, upgradeableHost.getUpgrades()); - } catch (Exception e) { - Logger.EAP$LOGGER.error("反射调用setupUpgrades失败", e); - return false; - } - - // 使用反射或接口设置工具箱 - if (menu instanceof IUpgradeableMenuCompat compatMenu) { - compatMenu.setCompatToolbox(toolbox); - } - return true; - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("初始化PatternProviderMenu升级功能时出错", e); - } - - return false; - } - - /** - * 为Screen添加升级面板(如果需要的话) - * @param widgets 小部件映射 - * @param menu 菜单实例 - * @param style 屏幕样式 - * @return 是否成功添加 - */ - public static boolean addUpgradePanelToScreen(Object widgets, Object menu, ScreenStyle style) { - if (!shouldAddUpgradePanelToScreen()) { - return false; - } - - try { - if (menu instanceof IUpgradeableMenuCompat compatMenu) { - try { - // 使用反射获取widgets的add方法 - 尝试不同的方法签名 - var widgetsClass = widgets.getClass(); - var addMethod = widgetsClass.getDeclaredMethod("add", String.class, Object.class); - addMethod.setAccessible(true); - - // 获取升级槽位 - var menuClass = menu.getClass(); - var getSlotsMethod = menuClass.getMethod("getSlots", SlotSemantics.class); - @SuppressWarnings("unchecked") - List upgradeSlots = (List) getSlotsMethod.invoke(menu, SlotSemantics.UPGRADE); - - // 添加升级面板 - UpgradesPanel upgradesPanel = new UpgradesPanel(upgradeSlots, () -> getCompatibleUpgrades(compatMenu)); - addMethod.invoke(widgets, "upgrades", upgradesPanel); - - // 添加工具箱面板(如果存在) - ToolboxMenu toolbox = compatMenu.getCompatToolbox(); - if (toolbox != null && toolbox.isPresent()) { - ToolboxPanel toolboxPanel = new ToolboxPanel(style, toolbox.getName()); - addMethod.invoke(widgets, "toolbox", toolboxPanel); - } - return true; - } catch (NoSuchMethodException e) { - // 尝试其他可能的方法签名 - try { - var widgetsClass = widgets.getClass(); - var putMethod = widgetsClass.getDeclaredMethod("put", String.class, Object.class); - putMethod.setAccessible(true); - - // 获取升级槽位 - var menuClass = menu.getClass(); - var getSlotsMethod = menuClass.getMethod("getSlots", SlotSemantics.class); - @SuppressWarnings("unchecked") - List upgradeSlots = (List) getSlotsMethod.invoke(menu, SlotSemantics.UPGRADE); - - // 添加升级面板 - UpgradesPanel upgradesPanel = new UpgradesPanel(upgradeSlots, () -> getCompatibleUpgrades(compatMenu)); - putMethod.invoke(widgets, "upgrades", upgradesPanel); - - // 添加工具箱面板(如果存在) - ToolboxMenu toolbox = compatMenu.getCompatToolbox(); - if (toolbox != null && toolbox.isPresent()) { - ToolboxPanel toolboxPanel = new ToolboxPanel(style, toolbox.getName()); - putMethod.invoke(widgets, "toolbox", toolboxPanel); - } - return true; - } catch (Exception e2) { - Logger.EAP$LOGGER.error("反射调用widgets方法失败", e2); - return false; - } - } - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("为PatternProviderScreen添加升级面板时出错", e); - } - - return false; - } - - /** - * 获取兼容的升级列表 - */ - private static List getCompatibleUpgrades(IUpgradeableMenuCompat menu) { - var list = new ArrayList(); - list.add(GuiText.CompatibleUpgrades.text()); - - try { - IUpgradeInventory upgrades = menu.getCompatUpgrades(); - if (upgrades != null) { - list.addAll(appeng.api.upgrades.Upgrades.getTooltipLinesForMachine(upgrades.getUpgradableItem())); - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("获取兼容升级列表时出错", e); - } - - return list; - } - + /** * 兼容性升级菜单接口 */ diff --git a/src/main/java/com/extendedae_plus/mixin/MixinConditions.java b/src/main/java/com/extendedae_plus/mixin/MixinConditions.java index dbf7799..61e16ca 100644 --- a/src/main/java/com/extendedae_plus/mixin/MixinConditions.java +++ b/src/main/java/com/extendedae_plus/mixin/MixinConditions.java @@ -1,5 +1,6 @@ package com.extendedae_plus.mixin; +import com.extendedae_plus.util.ModCheckUtils; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -24,70 +25,33 @@ public class MixinConditions implements IMixinConfigPlugin { @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - // 对于升级相关的Mixin,检查appflux是否存在 - if (mixinClassName.contains("PatternProviderMenuUpgradesMixin") || - mixinClassName.contains("PatternProviderLogicUpgradesMixin") || - mixinClassName.contains("PatternProviderLogicHostUpgradesMixin")) { - - try { - // 检查ModList是否已初始化 - if (net.minecraftforge.fml.ModList.get() == null) { - System.out.println("[ExtendedAE_Plus] ModList未初始化,默认应用升级Mixin: " + mixinClassName); - return true; // 修改策略:未初始化时默认应用,运行时再检查 - } - - boolean appfluxExists = net.minecraftforge.fml.ModList.get().isLoaded("appflux"); - boolean shouldApply = !appfluxExists; - - System.out.println("[ExtendedAE_Plus] 升级Mixin检查: " + mixinClassName + - ", appflux存在: " + appfluxExists + - ", 应用Mixin: " + shouldApply); - + try { + // === MAE2 兼容 === + if (mixinClassName.contains("CraftingCPUClusterMixin")) { + boolean shouldApply = !ModCheckUtils.isLoaded(ModCheckUtils.MODID_MAE2); + log(mixinClassName, "MAE2", shouldApply); return shouldApply; - } catch (Exception e) { - System.out.println("[ExtendedAE_Plus] ModList检查失败,默认应用升级Mixin: " + mixinClassName); - return true; // 修改策略:出错时默认应用,运行时再检查 } - } - - // 对于appflux相关的Mixin,总是加载但在运行时检查条件 - if (mixinClassName.contains("AppfluxPatternProviderLogicMixin")) { - System.out.println("[ExtendedAE_Plus] 总是加载appflux Mixin,运行时检查条件: " + mixinClassName); - return true; // 总是加载,在Mixin内部进行运行时检查 - } - - // 对于InterfaceLogicUpgradesMixin,总是加载但在运行时检查条件 - if (mixinClassName.contains("InterfaceLogicUpgradesMixin")) { - System.out.println("[ExtendedAE_Plus] 总是加载Interface升级Mixin,运行时检查条件: " + mixinClassName); - return true; // 总是加载,在Mixin内部进行运行时检查 - } - - // 对于CraftingCPUClusterMixin,检查MAE2是否存在 - if (mixinClassName.contains("CraftingCPUClusterMixin")) { - try { - // 检查ModList是否已初始化 - if (net.minecraftforge.fml.ModList.get() == null) { - System.out.println("[ExtendedAE_Plus] ModList未初始化,默认应用CraftingCPU Mixin: " + mixinClassName); - return true; // 未初始化时默认应用 - } - - boolean mae2Exists = net.minecraftforge.fml.ModList.get().isLoaded("mae2"); - boolean shouldApply = !mae2Exists; - - System.out.println("[ExtendedAE_Plus] CraftingCPU Mixin检查: " + mixinClassName + - ", MAE2存在: " + mae2Exists + - ", 应用Mixin: " + shouldApply); - + + // === AAE 兼容 === + if (mixinClassName.startsWith("com.extendedae_plus.mixin.advancedae")) { + boolean shouldApply = ModCheckUtils.isLoaded(ModCheckUtils.MODID_AAE); + log(mixinClassName, "aae", shouldApply); return shouldApply; - } catch (Exception e) { - System.out.println("[ExtendedAE_Plus] ModList检查失败,默认跳过CraftingCPU Mixin: " + mixinClassName); - return false; // 出错时默认跳过,避免冲突 } + + // === GuideME 版本兼容 === + if (mixinClassName.startsWith("com.extendedae_plus.mixin.guideme.")) { + boolean shouldApply = ModCheckUtils.isLoadedAndLowerThan(ModCheckUtils.MODID_GUIDEME, "20.1.14"); + logVersion(mixinClassName, "GuideME", ModCheckUtils.getVersion(ModCheckUtils.MODID_GUIDEME), "20.1.14", shouldApply); + return shouldApply; + } + + return true; + } catch (Exception e) { + System.err.println("[ExtendedAE_Plus] 检查 Mixin 条件时出错: " + e.getMessage()); + return true; // 出错默认加载,避免意外禁用 } - - // 其他Mixin正常应用 - System.out.println("[ExtendedAE_Plus] 加载Mixin: " + mixinClassName); - return true; } @Override @@ -109,4 +73,15 @@ public class MixinConditions implements IMixinConfigPlugin { public void postApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { // 应用后调用 } + + // === 日志方法 === + private void log(String mixin, String mod, boolean apply) { + System.out.printf("[ExtendedAE_Plus] 模组 %s 存在: %s, 应用 Mixin: %s, Mixin类:%s%n", + mod, ModCheckUtils.isLoaded(mod), apply, mixin); + } + + private void logVersion(String mixin, String mod, String detected, String target, boolean apply) { + System.out.printf("[ExtendedAE_Plus] 模组 %s 版本检测: 当前 %s, 目标 < %s, 应用 Mixin: %s%n", + mod, detected, target, apply); + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuUpgradesMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuUpgradesMixin.java deleted file mode 100644 index 01ef29c..0000000 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuUpgradesMixin.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.extendedae_plus.mixin.ae2.menu; - -import appeng.api.upgrades.IUpgradeInventory; -import appeng.api.upgrades.IUpgradeableObject; -import appeng.helpers.patternprovider.PatternProviderLogic; -import appeng.helpers.patternprovider.PatternProviderLogicHost; -import appeng.menu.AEBaseMenu; -import appeng.menu.ToolboxMenu; -import appeng.menu.implementations.PatternProviderMenu; -import com.extendedae_plus.api.bridge.IUpgradableMenu; -import com.extendedae_plus.compat.UpgradeSlotCompat; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.inventory.MenuType; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(value = PatternProviderMenu.class, priority = 2000, remap = false) -public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implements IUpgradableMenu { - @Final - @Shadow protected PatternProviderLogic logic; - - @Unique - private ToolboxMenu eap$toolbox; - - @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", - at = @At("TAIL")) - private void eap$initUpgrades(MenuType menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { - // 只有在应该启用升级卡槽时才初始化 - if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) { - return; - } - - this.eap$toolbox = new ToolboxMenu(this); - this.setupUpgrades(((IUpgradeableObject) host).getUpgrades()); - } - - @Override - public ToolboxMenu getToolbox() { - if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) { - return null; - } - return this.eap$toolbox; - } - - @Override - public IUpgradeInventory getUpgrades() { - if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) { - return appeng.api.upgrades.UpgradeInventories.empty(); - } - return ((IUpgradeableObject) this.logic).getUpgrades(); - } - - public PatternProviderMenuUpgradesMixin(MenuType menuType, int id, Inventory playerInventory, Object host) { - super(menuType, id, playerInventory, host); - } -} diff --git a/src/main/java/com/extendedae_plus/util/ModCheckUtils.java b/src/main/java/com/extendedae_plus/util/ModCheckUtils.java new file mode 100644 index 0000000..26ee901 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/ModCheckUtils.java @@ -0,0 +1,81 @@ +package com.extendedae_plus.util; + +import net.minecraftforge.fml.loading.LoadingModList; +import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; + +/** + * Forge 加载阶段的 Mod 检测工具 + * 适用于 MixinConfigPlugin 阶段使用 + * 包含版本比较工具 + */ +public class ModCheckUtils { + + private static final LoadingModList MOD_LIST = LoadingModList.get(); + + public static final String + MODID_JEI = "jei", + MODID_EMI = "emi", + MODID_AE = "ae2", + MODID_AAE = "advanced_ae", + MODID_AE2WTLIB = "ae2wtlib", + MODID_FTB_TEAMS = "ftbteams", + MODID_APPFLUX = "appflux", + MODID_GUIDEME = "guideme", + MODID_MAE2 = "mae2"; + + /** + * 检查指定模组是否存在 + */ + public static boolean isLoaded(String modid) { + return MOD_LIST != null && MOD_LIST.getModFileById(modid) != null; + } + + /** + * 获取模组版本号(x.x.x),若不存在则返回 "0.0.0" + */ + public static String getVersion(String modid) { + if (MOD_LIST == null) return "0.0.0"; + ModFileInfo file = MOD_LIST.getModFileById(modid); + if (file == null || file.getMods().isEmpty()) return "0.0.0"; + return file.getMods().get(0).getVersion().toString(); + } + + /** + * 检查模组是否存在且版本低于指定版本 + */ + public static boolean isLoadedAndLowerThan(String modid, String targetVersion) { + if (!isLoaded(modid)) return false; + return isVersionLower(getVersion(modid), targetVersion); + } + + /** + * 比较两个版本号 + * + * @param current 当前版本号,格式 x.x.x + * @param target 目标版本号,格式 x.x.x + * @return true 如果 current < target,否则 false + */ + public static boolean isVersionLower(String current, String target) { + if (current == null || target == null) return false; + + String[] curParts = current.split("\\."); + String[] tarParts = target.split("\\."); + + for (int i = 0; i < 3; i++) { + int curNum = i < curParts.length ? parse(curParts[i]) : 0; + int tarNum = i < tarParts.length ? parse(tarParts[i]) : 0; + + if (curNum < tarNum) return true; + if (curNum > tarNum) return false; + } + return false; // 相等则不小于 + } + + private static int parse(String s) { + try { + return Integer.parseInt(s.replaceAll("[^0-9]", "")); + } catch (Exception e) { + return 0; + } + } +}