重写mixin plugin, 修正逻辑, 去掉无用内容

This commit is contained in:
C-H716 2025-10-20 23:33:20 +08:00
parent 4dfba61426
commit 1d115c46e0
4 changed files with 116 additions and 268 deletions

View File

@ -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<Slot> upgradeSlots = (List<Slot>) 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<Slot> upgradeSlots = (List<Slot>) 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<Component> getCompatibleUpgrades(IUpgradeableMenuCompat menu) {
var list = new ArrayList<Component>();
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;
}
/**
* 兼容性升级菜单接口
*/

View File

@ -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);
}
}

View File

@ -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 = "<init>(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);
}
}

View File

@ -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;
}
}
}