优化appflux升级槽兼容

This commit is contained in:
GaLi 2026-03-26 11:05:00 +08:00
parent 7d621af169
commit 38b06eb484
10 changed files with 263 additions and 233 deletions

View File

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

View File

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

View File

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

View File

@ -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<C extends PatternProviderMenu> extends AEBaseScreen<C> {
public PatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Inject(method = "<init>", 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<C extends PatternProviderMenu>
this.setTextContent(AEBaseScreen.TEXT_ID_DIALOG_TITLE, t);
}
}
@Unique
private List<Component> eap$getCompatibleUpgrades() {
var list = new ArrayList<Component>();
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;
}
}

View File

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

View File

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

View File

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

View File

@ -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<C extends PatternProviderMenu> extends AEBaseScreen<C> {
public PatternProviderScreenCompatMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Inject(method = "<init>", 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<Component> eap$getCompatibleUpgrades() {
var list = new ArrayList<Component>();
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;
}
}

View File

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

View File

@ -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",