diff --git a/build.gradle b/build.gradle index 5e8862f..d60967a 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,7 @@ dependencies { modImplementation "appeng:appliedenergistics2-forge:${ae2_version}" modImplementation "org.appliedenergistics:guideme:${guideme_version}" modImplementation "curse.maven:applied-energistics-2-wireless-terminals-459929:${wireless_terminals_version}" - modImplementation "curse.maven:applied-flux-965012:7072853" + modCompileOnly "curse.maven:applied-flux-965012:7072853" modImplementation "curse.maven:mega-cells-622112:${mega_cells_version}" //mae2 diff --git a/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java b/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java index 69ba585..8ec2f1c 100644 --- a/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java +++ b/src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java @@ -3,14 +3,31 @@ package com.extendedae_plus.compat; import appeng.api.upgrades.IUpgradeInventory; import net.minecraftforge.fml.ModList; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + /** * 升级卡槽兼容性管理类 - * 检测ExtendedAE-appflux模组是否存在,如果存在则使用其升级卡槽功能 - * 否则使用我们自己的实现 + * 统一管理: + * 1. 是否由我们自己提供升级槽 + * 2. appflux存在时是否复用其升级槽 + * 3. appflux PatternProviderLogic 的反射访问入口 */ -public class UpgradeSlotCompat { +public final class UpgradeSlotCompat { private static final String APPFLUX_MOD_ID = "appflux"; - + private static final int LOCAL_PATTERN_PROVIDER_UPGRADE_SLOTS = 2; + private static final int APPFLUX_PATTERN_PROVIDER_UPGRADE_SLOTS = 2; + private static final String[] APPFLUX_UPGRADES_FIELD_NAMES = { "af_upgrades", "af_$upgrades" }; + private static final String[] APPFLUX_UPGRADES_CHANGED_METHOD_NAMES = { "af_onUpgradesChanged", "af_$onUpgradesChanged" }; + + private static Field patternProviderAppfluxUpgradesField; + private static boolean patternProviderAppfluxUpgradesFieldResolved; + private static Method patternProviderAppfluxUpgradesChangedMethod; + private static boolean patternProviderAppfluxUpgradesChangedMethodResolved; + + private UpgradeSlotCompat() { + } + /** * 检测Applied Flux模组是否存在 * @return true如果存在,false如果不存在 @@ -18,16 +35,36 @@ public class UpgradeSlotCompat { public static boolean isAppfluxPresent() { return ModList.get().isLoaded(APPFLUX_MOD_ID); } - + + /** + * 是否由我们自己提供升级槽实现。 + */ + public static boolean usesDedicatedUpgradeSlots() { + return !isAppfluxPresent(); + } + + /** + * 是否应当复用 appflux 注入到 PatternProviderLogic 上的升级槽。 + */ + public static boolean usesAppfluxUpgradeSlots() { + return isAppfluxPresent(); + } + /** * 检测是否应该启用我们的升级卡槽功能 * @return true如果应该启用,false如果检测到appflux模组存在 */ public static boolean shouldEnableUpgradeSlots() { - boolean appfluxExists = isAppfluxPresent(); - return !appfluxExists; + return usesDedicatedUpgradeSlots(); } - + + /** + * 是否需要持久化和管理我们本地创建的升级槽。 + */ + public static boolean shouldManageLocalUpgradeInventory() { + return usesDedicatedUpgradeSlots(); + } + /** * 检测是否应该启用频道卡功能 * 频道卡是我们独有的功能,即使appflux存在也应该启用 @@ -36,19 +73,105 @@ public class UpgradeSlotCompat { public static boolean shouldEnableChannelCard() { return true; // 频道卡功能总是启用,因为appflux没有实现这个功能 } - + + /** + * appflux 存在时,我们仍然需要监听其升级槽变化来驱动额外的兼容逻辑。 + */ + public static boolean shouldListenToAppfluxUpgrades() { + return usesAppfluxUpgradeSlots(); + } + /** * 检测是否应该在Screen中添加升级面板 * @return true如果应该添加,false如果检测到appflux模组存在 */ public static boolean shouldAddUpgradePanelToScreen() { - return shouldEnableUpgradeSlots(); + return usesDedicatedUpgradeSlots(); } - /** - * 兼容性升级菜单接口 - */ - public interface IUpgradeableMenuCompat { - IUpgradeInventory getCompatUpgrades(); + public static int getPatternProviderLocalUpgradeSlots() { + return LOCAL_PATTERN_PROVIDER_UPGRADE_SLOTS; + } + + public static int getPatternProviderAppfluxUpgradeSlots() { + return APPFLUX_PATTERN_PROVIDER_UPGRADE_SLOTS; + } + + public static IUpgradeInventory getPatternProviderAppfluxUpgrades(Object logicInstance) { + Field field = resolvePatternProviderAppfluxUpgradesField(logicInstance.getClass()); + if (field == null) { + return null; + } + + try { + Object value = field.get(logicInstance); + return value instanceof IUpgradeInventory inventory ? inventory : null; + } catch (IllegalAccessException e) { + return null; + } + } + + public static boolean setPatternProviderAppfluxUpgrades(Object logicInstance, IUpgradeInventory inventory) { + Field field = resolvePatternProviderAppfluxUpgradesField(logicInstance.getClass()); + if (field == null) { + return false; + } + + try { + field.set(logicInstance, inventory); + return true; + } catch (IllegalAccessException e) { + return false; + } + } + + public static boolean invokePatternProviderAppfluxUpgradesChanged(Object logicInstance) throws ReflectiveOperationException { + Method method = resolvePatternProviderAppfluxUpgradesChangedMethod(logicInstance.getClass()); + if (method == null) { + return false; + } + + method.invoke(logicInstance); + return true; + } + + private static Field resolvePatternProviderAppfluxUpgradesField(Class logicClass) { + if (!patternProviderAppfluxUpgradesFieldResolved) { + patternProviderAppfluxUpgradesField = findField(logicClass, APPFLUX_UPGRADES_FIELD_NAMES); + patternProviderAppfluxUpgradesFieldResolved = true; + } + return patternProviderAppfluxUpgradesField; + } + + private static Method resolvePatternProviderAppfluxUpgradesChangedMethod(Class logicClass) { + if (!patternProviderAppfluxUpgradesChangedMethodResolved) { + patternProviderAppfluxUpgradesChangedMethod = findMethod(logicClass, APPFLUX_UPGRADES_CHANGED_METHOD_NAMES); + patternProviderAppfluxUpgradesChangedMethodResolved = true; + } + return patternProviderAppfluxUpgradesChangedMethod; + } + + private static Field findField(Class owner, String[] candidates) { + for (String candidate : candidates) { + try { + Field field = owner.getDeclaredField(candidate); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException ignored) { + } + } + return null; + } + + private static Method findMethod(Class owner, String[] candidates) { + for (String candidate : candidates) { + try { + Method method = owner.getDeclaredMethod(candidate); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException ignored) { + } + } + return null; } } diff --git a/src/main/java/com/extendedae_plus/mixin/MixinConditions.java b/src/main/java/com/extendedae_plus/mixin/MixinConditions.java index d3dfac4..00c171e 100644 --- a/src/main/java/com/extendedae_plus/mixin/MixinConditions.java +++ b/src/main/java/com/extendedae_plus/mixin/MixinConditions.java @@ -36,6 +36,11 @@ public class MixinConditions implements IMixinConfigPlugin { return ModCheckUtils.isLoaded(ModCheckUtils.MODID_AAE); } + // === AppFlux 兼容 === + if (mixinClassName.startsWith("com.extendedae_plus.mixin.appflux")) { + return ModCheckUtils.isLoaded(ModCheckUtils.MODID_APPFLUX); + } + // === GuideME 版本兼容 === if (mixinClassName.startsWith("com.extendedae_plus.mixin.guideme.")) { return ModCheckUtils.isLoadedAndLowerThan(ModCheckUtils.MODID_GUIDEME, "20.1.14"); diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/patternProvider/PatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/patternProvider/PatternProviderScreenMixin.java index 33f07d4..5ff85bc 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/patternProvider/PatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/patternProvider/PatternProviderScreenMixin.java @@ -1,22 +1,48 @@ package com.extendedae_plus.mixin.ae2.client.gui.patternProvider; +import appeng.api.upgrades.IUpgradeableObject; +import appeng.api.upgrades.Upgrades; import appeng.client.gui.AEBaseScreen; import appeng.client.gui.implementations.PatternProviderScreen; import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.UpgradesPanel; +import appeng.core.localization.GuiText; +import appeng.menu.SlotSemantics; import appeng.menu.implementations.PatternProviderMenu; +import com.extendedae_plus.compat.UpgradeSlotCompat; +import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAccessor; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import org.spongepowered.asm.mixin.Mixin; +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; +import java.util.ArrayList; +import java.util.List; + @Mixin(PatternProviderScreen.class) public abstract class PatternProviderScreenMixin extends AEBaseScreen { public PatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) { super(menu, playerInventory, title, style); } + @Inject(method = "", at = @At("TAIL")) + private void eap$initCompatUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { + if (!UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) { + return; + } + + try { + this.widgets.add("upgrades", new UpgradesPanel( + menu.getSlots(SlotSemantics.UPGRADE), + this::eap$getCompatibleUpgrades)); + } catch (Exception e) { + com.extendedae_plus.util.Logger.EAP$LOGGER.error("PatternProviderScreen兼容性升级面板初始化失败", e); + } + } + /** * 显示样板供应器的customName */ @@ -27,4 +53,23 @@ public abstract class PatternProviderScreenMixin this.setTextContent(AEBaseScreen.TEXT_ID_DIALOG_TITLE, t); } } + + @Unique + private List eap$getCompatibleUpgrades() { + var list = new ArrayList(); + list.add(GuiText.CompatibleUpgrades.text()); + + try { + if (((PatternProviderMenuAccessor) this.menu).eap$logic() instanceof IUpgradeableObject upgradeableLogic) { + var upgrades = upgradeableLogic.getUpgrades(); + if (upgrades != null) { + list.addAll(Upgrades.getTooltipLinesForMachine(upgrades.getUpgradableItem())); + } + } + } catch (Exception e) { + com.extendedae_plus.util.Logger.EAP$LOGGER.error("获取兼容升级列表失败", e); + } + + return list; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderCompatMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderCompatMixin.java index 2f11276..9751407 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderCompatMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderCompatMixin.java @@ -9,7 +9,6 @@ import com.extendedae_plus.compat.UpgradeSlotCompat; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; import org.spongepowered.asm.mixin.Mixin; -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; @@ -21,9 +20,7 @@ import static com.extendedae_plus.util.Logger.EAP$LOGGER; * 优先级设置为500,低于appflux的默认优先级,避免冲突 */ @Mixin(value = PatternProviderMenu.class, priority = 500, remap = false) -public abstract class PatternProviderCompatMixin extends AEBaseMenu implements UpgradeSlotCompat.IUpgradeableMenuCompat { - @Unique - private IUpgradeInventory eap$compatUpgrades; +public abstract class PatternProviderCompatMixin extends AEBaseMenu { public PatternProviderCompatMixin(MenuType menuType, int id, Inventory playerInventory, Object host) { super(menuType, id, playerInventory, host); @@ -33,12 +30,10 @@ public abstract class PatternProviderCompatMixin extends AEBaseMenu implements U at = @At("TAIL")) private void eap$initCompatUpgrades(MenuType menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { try { - // 检测是否应该启用升级卡槽功能 - if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) { - // 直接初始化升级功能 - if (host instanceof IUpgradeableObject upgradeableHost) { - this.eap$compatUpgrades = upgradeableHost.getUpgrades(); - this.setupUpgrades(this.eap$compatUpgrades); + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { + if (host.getLogic() instanceof IUpgradeableObject upgradeableLogic) { + IUpgradeInventory upgrades = upgradeableLogic.getUpgrades(); + this.setupUpgrades(upgrades); } } } catch (Exception e) { @@ -46,9 +41,4 @@ public abstract class PatternProviderCompatMixin extends AEBaseMenu implements U EAP$LOGGER.error("PatternProviderMenu兼容性升级初始化失败", e); } } - - @Override - public IUpgradeInventory getCompatUpgrades() { - return this.eap$compatUpgrades; - } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java index c59c654..d91d133 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java @@ -33,12 +33,11 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.lang.reflect.Field; import java.util.List; /** * PatternProviderLogic的兼容性Mixin - * 优先级设置为1500,在appflux之后应用 + * 优先级设置为500,在appflux之前应用 * 根据appflux是否存在来决定是否实现IUpgradeableObject接口 */ @Mixin(value = PatternProviderLogic.class, priority = 500, remap = false) @@ -77,9 +76,6 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Unique private boolean eap$compatVirtualCraftingEnabled = false; - @Unique - private static Field eap$compatAppfluxUpgradesField; - @Shadow public abstract IGrid getGrid(); @@ -159,13 +155,11 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj } } - // 监听appflux的升级变化 - 通过注入到appflux的af_$onUpgradesChanged方法 - @Inject(method = "af_$onUpgradesChanged", at = @At("TAIL"), remap = false, require = 0) - private void eap$onAppfluxUpgradesChanged(CallbackInfo ci) { + @Unique + private void eap$compatOnExternalUpgradesChanged() { try { eap$compatSyncVirtualCraftingState(); if (UpgradeSlotCompat.shouldEnableChannelCard()) { - // 升级变更,重置并尝试初始化频道卡 eap$compatLastChannel = -1; eap$compatHasInitialized = false; eap$compatInitializeChannelLink(); @@ -175,25 +169,34 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj } } + // 监听 appflux 1.21.1 当前源码中的升级变化回调 + @Inject(method = "af_onUpgradesChanged", at = @At("TAIL"), remap = false, require = 0) + private void eap$onAppfluxUpgradesChanged(CallbackInfo ci) { + eap$compatOnExternalUpgradesChanged(); + } + + // 兼容旧命名,避免不同 appflux 版本导致注入失效 + @Inject(method = "af_$onUpgradesChanged", at = @At("TAIL"), remap = false, require = 0) + private void eap$onLegacyAppfluxUpgradesChanged(CallbackInfo ci) { + eap$compatOnExternalUpgradesChanged(); + } + @Inject(method = "(Lappeng/api/networking/IManagedGridNode;Lappeng/helpers/patternprovider/PatternProviderLogicHost;I)V", at = @At("TAIL")) private void eap$compatInitUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) { try { - boolean upgradeSlots = UpgradeSlotCompat.shouldEnableUpgradeSlots(); + boolean upgradeSlots = UpgradeSlotCompat.shouldManageLocalUpgradeInventory(); boolean channelCard = UpgradeSlotCompat.shouldEnableChannelCard(); - if (upgradeSlots) { - // 只有在升级槽功能启用时才创建升级槽 this.eap$compatUpgrades = UpgradeInventories.forMachine( - host.getTerminalIcon().getItem(), - 2, - this::eap$compatOnUpgradesChanged + host.getTerminalIcon().getItem(), + UpgradeSlotCompat.getPatternProviderLocalUpgradeSlots(), + this::eap$compatOnUpgradesChanged ); - } else if (channelCard) { - // 如果装了appflux,我们不创建自己的升级槽,而是监听appflux的升级槽 - } else { + } else if (!channelCard) { + this.eap$compatUpgrades = UpgradeInventories.empty(); } } catch (Exception e) { Logger.EAP$LOGGER.error("兼容性升级初始化失败", e); @@ -203,7 +206,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Inject(method = "writeToNBT", at = @At("TAIL")) private void eap$compatSaveUpgrades(CompoundTag tag, CallbackInfo ci) { try { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots() || UpgradeSlotCompat.shouldEnableChannelCard()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { this.eap$compatUpgrades.writeToNBT(tag, "compat_upgrades"); } } catch (Exception e) { @@ -214,15 +217,16 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Inject(method = "readFromNBT", at = @At("TAIL")) private void eap$compatLoadUpgrades(CompoundTag tag, CallbackInfo ci) { try { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots() || UpgradeSlotCompat.shouldEnableChannelCard()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { this.eap$compatUpgrades.readFromNBT(tag, "compat_upgrades"); - if (UpgradeSlotCompat.shouldEnableChannelCard()) { - eap$compatLastChannel = -1; - eap$compatHasInitialized = false; - eap$compatInitializeChannelLink(); - } - eap$compatSyncVirtualCraftingState(); } + + if (UpgradeSlotCompat.shouldEnableChannelCard()) { + eap$compatLastChannel = -1; + eap$compatHasInitialized = false; + eap$compatInitializeChannelLink(); + } + eap$compatSyncVirtualCraftingState(); } catch (Exception e) { Logger.EAP$LOGGER.error("兼容性升级加载失败", e); } @@ -231,7 +235,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Inject(method = "addDrops", at = @At("TAIL")) private void eap$compatDropUpgrades(List drops, CallbackInfo ci) { try { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots() || UpgradeSlotCompat.shouldEnableChannelCard()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { for (var stack : this.eap$compatUpgrades) { if (!stack.isEmpty()) { drops.add(stack); @@ -246,8 +250,10 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Inject(method = "clearContent", at = @At("TAIL")) private void eap$compatClearUpgrades(CallbackInfo ci) { try { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots() || UpgradeSlotCompat.shouldEnableChannelCard()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { this.eap$compatUpgrades.clear(); + } + if (UpgradeSlotCompat.shouldEnableChannelCard()) { eap$compatVirtualCraftingEnabled = false; } } catch (Exception e) { @@ -257,7 +263,7 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Override public IUpgradeInventory getUpgrades() { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { return this.eap$compatUpgrades != null ? this.eap$compatUpgrades : UpgradeInventories.empty(); } else { return eap$compatGetEffectiveUpgradeInventory(); @@ -396,29 +402,17 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj @Unique private IUpgradeInventory eap$compatGetEffectiveUpgradeInventory() { - if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) { + if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) { return this.eap$compatUpgrades; } - if (!UpgradeSlotCompat.shouldEnableChannelCard()) { + if (!UpgradeSlotCompat.shouldListenToAppfluxUpgrades()) { return null; } - if (this.eap$compatUpgrades != null && this.eap$compatUpgrades != UpgradeInventories.empty()) { - return this.eap$compatUpgrades; - } - - try { - if (eap$compatAppfluxUpgradesField == null) { - eap$compatAppfluxUpgradesField = PatternProviderLogic.class.getDeclaredField("af_$upgrades"); - eap$compatAppfluxUpgradesField.setAccessible(true); - } - Object value = eap$compatAppfluxUpgradesField.get(this); - if (value instanceof IUpgradeInventory inventory) { - return inventory; - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("获取appflux升级槽失败", e); + IUpgradeInventory inventory = UpgradeSlotCompat.getPatternProviderAppfluxUpgrades(this); + if (inventory != null) { + return inventory; } return UpgradeInventories.empty(); diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicHostCompatMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicHostCompatMixin.java deleted file mode 100644 index f6cdee4..0000000 --- a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicHostCompatMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.extendedae_plus.mixin.ae2.compat; - -import appeng.api.upgrades.IUpgradeInventory; -import appeng.api.upgrades.IUpgradeableObject; -import appeng.api.upgrades.UpgradeInventories; -import appeng.helpers.patternprovider.PatternProviderLogic; -import appeng.helpers.patternprovider.PatternProviderLogicHost; -import com.extendedae_plus.compat.UpgradeSlotCompat; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -/** - * PatternProviderLogicHost的兼容性Mixin - * 优先级设置为500,避免与appflux冲突 - */ -@Mixin(value = PatternProviderLogicHost.class, priority = 500, remap = false) -public interface PatternProviderLogicHostCompatMixin extends IUpgradeableObject { - @Shadow PatternProviderLogic getLogic(); - - @Override - default IUpgradeInventory getUpgrades() { - if (!UpgradeSlotCompat.shouldEnableUpgradeSlots() && !UpgradeSlotCompat.shouldEnableChannelCard()) { - return UpgradeInventories.empty(); - } - return ((IUpgradeableObject) this.getLogic()).getUpgrades(); - } -} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderScreenCompatMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderScreenCompatMixin.java deleted file mode 100644 index 63313ed..0000000 --- a/src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderScreenCompatMixin.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.extendedae_plus.mixin.ae2.compat; - -import appeng.api.upgrades.Upgrades; -import appeng.client.gui.AEBaseScreen; -import appeng.client.gui.implementations.PatternProviderScreen; -import appeng.client.gui.style.ScreenStyle; -import appeng.client.gui.widgets.UpgradesPanel; -import appeng.core.localization.GuiText; -import appeng.menu.SlotSemantics; -import appeng.menu.implementations.PatternProviderMenu; -import com.extendedae_plus.compat.UpgradeSlotCompat; -import com.extendedae_plus.util.Logger; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.player.Inventory; -import org.spongepowered.asm.mixin.Mixin; -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; - -import java.util.ArrayList; -import java.util.List; - -/** - * PatternProviderScreen的兼容性Mixin - * 优先级设置为500,避免与appflux冲突 - */ -@Mixin(value = PatternProviderScreen.class, priority = 500, remap = false) -public abstract class PatternProviderScreenCompatMixin extends AEBaseScreen { - public PatternProviderScreenCompatMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) { - super(menu, playerInventory, title, style); - } - - @Inject(method = "", at = @At("TAIL")) - private void eap$initCompatUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { - try { - // 检测是否应该添加升级面板 - if (UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) { - // 直接添加升级面板,不使用复杂的反射 - this.eap$addUpgradePanelDirect(menu, style); - } - } catch (Exception e) { - // 静默处理异常,确保不会因为升级功能导致崩溃 - Logger.EAP$LOGGER.error("PatternProviderScreen兼容性升级面板初始化失败", e); - } - } - - @Unique - private void eap$addUpgradePanelDirect(PatternProviderMenu menu, ScreenStyle style) { - try { - // 直接添加升级面板 - this.widgets.add("upgrades", new UpgradesPanel( - menu.getSlots(SlotSemantics.UPGRADE), - this::eap$getCompatibleUpgrades)); - } catch (Exception e) { - Logger.EAP$LOGGER.error("直接添加升级面板失败", e); - } - } - - @Unique - private List eap$getCompatibleUpgrades() { - var list = new ArrayList(); - list.add(GuiText.CompatibleUpgrades.text()); - - try { - if (menu instanceof UpgradeSlotCompat.IUpgradeableMenuCompat compatMenu) { - var upgrades = compatMenu.getCompatUpgrades(); - if (upgrades != null) { - list.addAll(Upgrades.getTooltipLinesForMachine(upgrades.getUpgradableItem())); - } - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("获取兼容升级列表失败", e); - } - - return list; - } -} diff --git a/src/main/java/com/extendedae_plus/mixin/appflux/AppfluxPatternProviderLogicMixin.java b/src/main/java/com/extendedae_plus/mixin/appflux/AppfluxPatternProviderLogicMixin.java index ffa890b..0971b21 100644 --- a/src/main/java/com/extendedae_plus/mixin/appflux/AppfluxPatternProviderLogicMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/appflux/AppfluxPatternProviderLogicMixin.java @@ -13,12 +13,9 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - /** - * 当appflux存在时,修改PatternProviderLogic的升级槽数量为2个 - * 优先级设置为2000,确保在appflux之后应用 + * 当 appflux 存在时,把它默认的 1 槽升级栏扩展为我们兼容层需要的 2 槽。 + * 优先级设置为 2000,确保在 appflux 自己初始化之后执行。 */ @Mixin(value = PatternProviderLogic.class, priority = 2000, remap = false) public class AppfluxPatternProviderLogicMixin { @@ -30,59 +27,42 @@ public class AppfluxPatternProviderLogicMixin { at = @At("TAIL")) private void eap$modifyAppfluxUpgradeSlots(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) { try { - if (host instanceof MirrorPatternProviderBlockEntity) { + if (host instanceof MirrorPatternProviderBlockEntity || !UpgradeSlotCompat.shouldListenToAppfluxUpgrades()) { return; } - // 只有当appflux存在且不启用我们的升级槽时才修改数量 - if (!UpgradeSlotCompat.shouldEnableUpgradeSlots() && UpgradeSlotCompat.shouldEnableChannelCard()) { + IUpgradeInventory currentUpgrades = UpgradeSlotCompat.getPatternProviderAppfluxUpgrades(this); + if (currentUpgrades == null) { + Logger.EAP$LOGGER.debug("未找到appflux升级槽字段,跳过升级槽兼容调整"); + return; + } - // 使用反射找到appflux的升级槽字段并替换 - try { - Field upgradesField = PatternProviderLogic.class.getDeclaredField("af_$upgrades"); - upgradesField.setAccessible(true); - IUpgradeInventory currentUpgrades = (IUpgradeInventory) upgradesField.get(this); - Method onUpgradesChanged = null; - try { - onUpgradesChanged = PatternProviderLogic.class.getDeclaredMethod("af_$onUpgradesChanged"); - onUpgradesChanged.setAccessible(true); - } catch (NoSuchMethodException ignored) { - } - - if (currentUpgrades != null) { + int targetSlots = UpgradeSlotCompat.getPatternProviderAppfluxUpgradeSlots(); + if (currentUpgrades.size() == targetSlots) { + return; + } - // 创建新的2槽升级槽 - Method finalOnUpgradesChanged = onUpgradesChanged; - IUpgradeInventory newUpgrades = UpgradeInventories.forMachine( - host.getTerminalIcon().getItem(), - 2, - () -> { - try { - if (finalOnUpgradesChanged != null) { - finalOnUpgradesChanged.invoke(this); - } - } catch (Exception e) { - Logger.EAP$LOGGER.error("调用appflux升级变更方法失败", e); - } - } - ); - - // 复制原有升级卡到新的升级槽 - for (int i = 0; i < Math.min(currentUpgrades.size(), newUpgrades.size()); i++) { - if (!currentUpgrades.getStackInSlot(i).isEmpty()) { - newUpgrades.insertItem(i, currentUpgrades.getStackInSlot(i).copy(), false); - } + IUpgradeInventory newUpgrades = UpgradeInventories.forMachine( + host.getTerminalIcon().getItem(), + targetSlots, + () -> { + try { + UpgradeSlotCompat.invokePatternProviderAppfluxUpgradesChanged(this); + } catch (Exception e) { + Logger.EAP$LOGGER.error("调用appflux升级变更方法失败", e); } - - // 替换升级槽 - upgradesField.set(this, newUpgrades); } - } catch (NoSuchFieldException e) { - Logger.EAP$LOGGER.debug("未找到appflux升级槽字段,跳过升级槽兼容调整"); - } catch (Exception e) { - Logger.EAP$LOGGER.error("反射修改appflux升级槽失败", e); + ); + + for (int i = 0; i < Math.min(currentUpgrades.size(), newUpgrades.size()); i++) { + if (!currentUpgrades.getStackInSlot(i).isEmpty()) { + newUpgrades.insertItem(i, currentUpgrades.getStackInSlot(i).copy(), false); } } + + if (!UpgradeSlotCompat.setPatternProviderAppfluxUpgrades(this, newUpgrades)) { + Logger.EAP$LOGGER.debug("设置appflux升级槽失败,跳过升级槽兼容调整"); + } } catch (Exception e) { Logger.EAP$LOGGER.error("AppfluxPatternProviderLogicMixin执行失败", e); } diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index 8b34f8e..ad76aee 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -18,7 +18,6 @@ "ae2.client.gui.patternProvider.PatternProviderHighlightCleanupMixin", "ae2.client.gui.patternProvider.PatternProviderScreenMixin", "ae2.client.gui.patternProvider.PatternProviderSmartFeaturesMixin", - "ae2.compat.PatternProviderScreenCompatMixin", "ae2.items.QuartzCuttingKnifeItemMixin", "ae2.menu.CraftConfirmMenuGoBackMixin", "extendedae.accessor.GuiExPatternTerminalAccessor", @@ -66,7 +65,6 @@ "ae2.autopattern.PatternProviderLogicContainsRedirectMixin", "ae2.compat.PatternProviderCompatMixin", "ae2.compat.PatternProviderLogicCompatMixin", - "ae2.compat.PatternProviderLogicHostCompatMixin", "ae2.helpers.InterfaceLogicChannelCardMixin", "ae2.helpers.InterfaceLogicTickerMixin", "ae2.helpers.InterfaceLogicUpgradesMixin",