优化appflux升级槽兼容

This commit is contained in:
GaLi 2026-03-26 12:02:45 +08:00
parent 9d73964196
commit 9d126e65a0
10 changed files with 253 additions and 337 deletions

View File

@ -0,0 +1,7 @@
package com.extendedae_plus.api.bridge;
import appeng.api.upgrades.IUpgradeInventory;
public interface PatternProviderLogicAppfluxBridge {
IUpgradeInventory eap$ensureAppfluxUpgradeSlots();
}

View File

@ -1,72 +1,123 @@
package com.extendedae_plus.compat;
import net.neoforged.fml.loading.FMLLoader;
import net.neoforged.fml.ModList;
/**
* 升级卡槽兼容性管理类
* 统一管理
* 1. 是否由我们自己提供升级槽
* 2. appflux存在时是否复用其升级槽
*/
public final class UpgradeSlotCompat {
private static Boolean APPFLUX_LOADED;
private static Boolean APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE;
private static final String APPFLUX_MOD_ID = "appflux";
private static final String APPFLUX_SCREEN_MIXIN = "com.glodblock.github.appflux.mixins.MixinPatternProviderScreen";
private static final int LOCAL_PATTERN_PROVIDER_UPGRADE_SLOTS = 2;
private static final int APPFLUX_PATTERN_PROVIDER_UPGRADE_SLOTS = 2;
private UpgradeSlotCompat() {}
private static Boolean appfluxLoaded;
private static Boolean appfluxPatternProviderMixinActive;
private static boolean isAppfluxLoaded() {
if (APPFLUX_LOADED == null) {
try {
APPFLUX_LOADED = ModList.get().isLoaded("appflux");
} catch (Throwable t) {
// 早期阶段或运行环境差异
APPFLUX_LOADED = false;
}
}
return APPFLUX_LOADED;
private UpgradeSlotCompat() {
}
/**
* 检测AppliedFlux的PatternProviderScreen mixin是否活跃
* 这比简单检查模组是否加载更准确
* 检测 Applied Flux 模组是否存在
*/
private static boolean isAppfluxPatternProviderMixinActive() {
if (APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE == null) {
public static boolean isAppfluxPresent() {
if (appfluxLoaded == null) {
try {
if (!isAppfluxLoaded()) {
APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE = false;
} else {
// 尝试检测AppliedFlux的mixin类是否存在
Class.forName("com.glodblock.github.appflux.mixins.MixinPatternProviderScreen");
APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE = true;
}
} catch (ClassNotFoundException e) {
APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE = false;
appfluxLoaded = ModList.get().isLoaded(APPFLUX_MOD_ID);
} catch (Throwable t) {
APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE = false;
appfluxLoaded = false;
}
}
return APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE;
return appfluxLoaded;
}
// 是否由我们提供升级槽当未安装 appflux
/**
* 是否由我们自己提供升级槽实现
*/
public static boolean usesDedicatedUpgradeSlots() {
return !isAppfluxPresent();
}
/**
* 是否应当复用 appflux 注入到 PatternProviderLogic 上的升级槽
*/
public static boolean usesAppfluxUpgradeSlots() {
return isAppfluxPresent();
}
/**
* 检测是否应该启用我们的升级卡槽功能
*/
public static boolean shouldEnableUpgradeSlots() {
return !isAppfluxLoaded();
return usesDedicatedUpgradeSlots();
}
// 是否启用频道卡支持两种情况下都启用
/**
* 是否需要持久化和管理我们本地创建的升级槽
*/
public static boolean shouldManageLocalUpgradeInventory() {
return usesDedicatedUpgradeSlots();
}
/**
* 频道卡是我们独有的功能即使 appflux 存在也应该启用
*/
public static boolean shouldEnableChannelCard() {
return true;
}
// 客户端界面是否需要显示升级面板
// 如果AppliedFlux的mixin活跃我们降低优先级让它处理
public static boolean shouldAddUpgradePanelToScreen() {
return true; // 总是尝试添加但在代码中检测冲突
/**
* appflux 存在时我们仍然需要监听其升级槽变化来驱动额外的兼容逻辑
*/
public static boolean shouldListenToAppfluxUpgrades() {
return usesAppfluxUpgradeSlots();
}
// 是否应该使用低优先级模式当AppliedFlux存在时
/**
* 客户端界面是否需要显示升级面板
*/
public static boolean shouldAddUpgradePanelToScreen() {
return usesDedicatedUpgradeSlots();
}
public static int getPatternProviderLocalUpgradeSlots() {
return LOCAL_PATTERN_PROVIDER_UPGRADE_SLOTS;
}
public static int getPatternProviderAppfluxUpgradeSlots() {
return APPFLUX_PATTERN_PROVIDER_UPGRADE_SLOTS;
}
/**
* 兼容主工程现有调用 appflux PatternProvider Screen mixin 会接管 UI 返回低优先级模式
*/
public static boolean shouldUseLowPriorityMode() {
return isAppfluxPatternProviderMixinActive();
}
// 获取推荐的mixin优先级
/**
* 兼容主工程现有调用保留旧的优先级推荐接口
*/
public static int getRecommendedMixinPriority() {
return isAppfluxPatternProviderMixinActive() ? 1500 : 2000;
return shouldUseLowPriorityMode() ? 1500 : 2000;
}
private static boolean isAppfluxPatternProviderMixinActive() {
if (appfluxPatternProviderMixinActive == null) {
try {
if (!isAppfluxPresent()) {
appfluxPatternProviderMixinActive = false;
} else {
Class.forName(APPFLUX_SCREEN_MIXIN);
appfluxPatternProviderMixinActive = true;
}
} catch (Throwable t) {
appfluxPatternProviderMixinActive = false;
}
}
return appfluxPatternProviderMixinActive;
}
}

View File

@ -38,6 +38,10 @@ public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
return isClassPresent("lu.kolja.expandedae.ExpandedAE");
}
private static boolean isAppfluxPresent() {
return isClassPresent("com.glodblock.github.appflux.AppFlux");
}
@Override
public void onLoad(String mixinPackage) { }
@ -46,6 +50,9 @@ public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if (!isAppfluxPresent() && mixinClassName.startsWith("com.extendedae_plus.mixin.appflux.")) {
return false;
}
if (!isJeiPresent()) {
// Disable all JEI package mixins and any mixins that reference JEI-only helpers
if (mixinClassName.startsWith("com.extendedae_plus.mixin.jei")) return false;
@ -81,4 +88,4 @@ public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
}
}

View File

@ -16,7 +16,6 @@ import appeng.menu.AEBaseMenu;
import appeng.menu.SlotSemantics;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.IStyleAccessor;
import com.extendedae_plus.compat.AppliedFluxCompat;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
@ -38,57 +37,43 @@ public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProvid
@Inject(method = "<init>", at = @At("TAIL"), remap = false)
private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) {
return;
}
// 若已安装 AppliedFlux则由 AE2/AppliedFlux 自己负责渲染升级面板避免我们重复添加导致界面显示两个槽
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (!UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
return;
}
// 使用改进的AppliedFlux兼容性检测
@SuppressWarnings("unchecked")
PatternProviderScreen<PatternProviderMenu> screen = (PatternProviderScreen<PatternProviderMenu>) (Object) this;
try {
this.widgets.add("upgrades", new UpgradesPanel(menu.getSlots(SlotSemantics.UPGRADE), this::eap$getCompatibleUpgrades));
} catch (IllegalStateException e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 升级面板已存在,跳过添加: {}", e.getMessage());
return;
}
boolean shouldSkip = AppliedFluxCompat.shouldSkipOurUpgradePanel(screen);
var sp = new SlotPosition();
sp.setBottom(84);
sp.setRight(1);
sp.setGrid(SlotGridLayout.BREAK_AFTER_3COLS);
var ws = new WidgetStyle();
ws.setRight(2);
ws.setBottom(90);
ws.setWidth(59);
ws.setHeight(66);
style.getSlots().put("TOOLBOX", sp);
((IStyleAccessor) style).getImages().put("toolbox", Blitter.texture("guis/extra_panels.png", 128, 128).src(69, 62, 59, 66));
((IStyleAccessor) style).getWidgets().put("toolbox", ws);
if (shouldSkip) {
} else {
// 检查是否已经存在upgrades widget
if (menu instanceof AEBaseMenu base
&& base instanceof com.extendedae_plus.api.bridge.IUpgradableMenu upg
&& upg.eap$getToolbox() != null
&& upg.eap$getToolbox().isPresent()) {
try {
// 尝试添加升级面板
this.widgets.add("upgrades", new UpgradesPanel(menu.getSlots(SlotSemantics.UPGRADE), this::eap$getCompatibleUpgrades));
this.widgets.add("toolbox", new ToolboxPanel(style, upg.eap$getToolbox().getName()));
} catch (IllegalStateException e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 升级面板已存在,跳过添加: {}", e.getMessage());
return; // 如果升级面板已存在不继续添加其他内容
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 工具箱面板已存在,跳过添加: {}", e.getMessage());
}
// 设置TOOLBOX样式完全按照AppliedFlux的方式
var sp = new SlotPosition();
sp.setBottom(84);
sp.setRight(1);
sp.setGrid(SlotGridLayout.BREAK_AFTER_3COLS);
var ws = new WidgetStyle();
ws.setRight(2);
ws.setBottom(90);
ws.setWidth(59);
ws.setHeight(66);
style.getSlots().put("TOOLBOX", sp);
((IStyleAccessor) style).getImages().put("toolbox", Blitter.texture("guis/extra_panels.png", 128, 128).src(69, 62, 59, 66));
((IStyleAccessor) style).getWidgets().put("toolbox", ws);
// 添加工具箱面板
if (menu instanceof AEBaseMenu base && base instanceof com.extendedae_plus.api.bridge.IUpgradableMenu upg && upg.eap$getToolbox() != null && upg.eap$getToolbox().isPresent()) {
try {
this.widgets.add("toolbox", new ToolboxPanel(style, upg.eap$getToolbox().getName()));
} catch (IllegalStateException e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 工具箱面板已存在,跳过添加: {}", e.getMessage());
}
}
}
}

View File

@ -23,6 +23,7 @@ import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.appflux.accessor.PatternProviderLogicAppfluxAccessor;
import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
@ -41,7 +42,7 @@ import java.util.UUID;
/**
* 样板供应器频道卡兼容实现
* - 未安装 appflux 提供 1 个升级槽并读取频道卡
* - 未安装 appflux 提供 2 个升级槽并读取频道卡
* - 安装 appflux 优先从 appflux 提供的升级槽读取频道卡
* - 建立到无线主站的网格连接
*/
@ -85,13 +86,12 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
at = @At("TAIL"))
private void eap$compatInit(IManagedGridNode mainNode, PatternProviderLogicHost host, int size, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 未安装AppliedFlux我们需要提供升级槽
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$compatUpgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(), 2, this::eap$compatOnUpgradesChanged);
} else {
// 安装了AppliedFlux我们不提供升级槽保留空的兼容槽用于备用
// AppFlux 的升级槽变更会通过 PatternProviderLogicUpgradesMixin bridge 回调到我们
host.getTerminalIcon().getItem(),
UpgradeSlotCompat.getPatternProviderLocalUpgradeSlots(),
this::eap$compatOnUpgradesChanged);
} else if (!UpgradeSlotCompat.shouldEnableChannelCard()) {
this.eap$compatUpgrades = UpgradeInventories.empty();
}
} catch (Throwable t) {
@ -113,20 +113,15 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
}
}
/**
* 实现 PatternProviderLogicUpgradeCompatBridge 接口
* PatternProviderLogicUpgradesMixin 在升级槽变更时调用
*/
@Override
public void eap$onCompatUpgradesChangedHook() {
this.eap$compatOnUpgradesChanged();
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$compatWrite(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$compatUpgrades.writeToNBT(tag, "compat_upgrades", registries);
}
} catch (Throwable t) {
@ -137,7 +132,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$compatRead(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$compatUpgrades.readFromNBT(tag, "compat_upgrades", registries);
}
// 无论哪种模式都重新初始化
@ -153,7 +148,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Inject(method = "addDrops", at = @At("TAIL"))
private void eap$compatDrops(List<ItemStack> drops, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
for (var s : this.eap$compatUpgrades) {
if (!s.isEmpty()) drops.add(s);
}
@ -166,7 +161,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Inject(method = "clearContent", at = @At("TAIL"))
private void eap$compatClear(CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$compatUpgrades.clear();
}
} catch (Throwable t) {
@ -282,33 +277,15 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
boolean found = false;
UUID owner = null;
IUpgradeInventory upgrades = null;
// 优先尝试从AppliedFlux获取升级槽如果安装了的话
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 安装了appflux优先使用appflux的升级槽
try {
// 更安全的方式获取AppliedFlux升级槽
upgrades = this.eap$getAppliedFluxUpgrades();
if (upgrades != null) {
} else {
ExtendedAELogger.LOGGER.warn("[样板供应器] 无法获取 appflux 升级槽,回退到兼容槽");
upgrades = this.eap$compatUpgrades;
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 获取 appflux 升级槽失败,回退到兼容槽", t);
upgrades = this.eap$compatUpgrades;
}
} else {
// 未安装appflux使用我们的兼容升级槽
IUpgradeInventory upgrades = UpgradeSlotCompat.shouldListenToAppfluxUpgrades()
? this.eap$getAppliedFluxUpgrades()
: this.eap$compatUpgrades;
if (upgrades == null) {
upgrades = this.eap$compatUpgrades;
}
// 双重保险如果主要方式失败尝试备用方式
if (upgrades == null || !this.eap$hasChannelCard(upgrades)) {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 如果我们的槽无频道卡尝试检查是否有AppliedFlux的槽
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
try {
IUpgradeInventory backupUpgrades = this.eap$getAppliedFluxUpgrades();
if (backupUpgrades != null && this.eap$hasChannelCard(backupUpgrades)) {
@ -317,7 +294,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
} catch (Throwable t) {
}
} else {
// 如果AppliedFlux的槽无频道卡尝试我们的兼容槽
if (this.eap$compatUpgrades != null && this.eap$hasChannelCard(this.eap$compatUpgrades)) {
upgrades = this.eap$compatUpgrades;
}
@ -434,21 +410,23 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
*/
@Unique
private IUpgradeInventory eap$getAppliedFluxUpgrades() {
if (!UpgradeSlotCompat.shouldListenToAppfluxUpgrades()) {
return null;
}
try {
// 检查当前对象是否实现了IUpgradeableObject接口
if (this instanceof IUpgradeableObject upgradeableObject) {
if ((Object) this instanceof IUpgradeableObject upgradeableObject) {
IUpgradeInventory upgrades = upgradeableObject.getUpgrades();
// 确保这不是我们自己的兼容升级槽
if (upgrades != null && upgrades != this.eap$compatUpgrades) {
return upgrades;
} else {
}
} else {
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 获取AppliedFlux升级槽时出错", t);
IUpgradeInventory upgrades = ((PatternProviderLogicAppfluxAccessor) (Object) this).eap$getAppfluxUpgrades();
if (upgrades != null && upgrades != this.eap$compatUpgrades) {
return upgrades;
}
} catch (Throwable ignored) {
}
return null;
}
@ -547,7 +525,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Unique
private IUpgradeInventory eap$compatGetEffectiveUpgrades() {
IUpgradeInventory upgrades;
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
upgrades = this.eap$compatUpgrades;
} else {
upgrades = this.eap$getAppliedFluxUpgrades();

View File

@ -56,7 +56,7 @@ public abstract class InterfaceLogicUpgradesMixin implements CompatUpgradeProvid
this.upgrades = UpgradeInventories.forMachine(is, targetSlots, this::eap$onUpgradesChanged);
// 设置兼容升级槽
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$compatUpgrades = this.upgrades;
}
}

View File

@ -5,11 +5,12 @@ import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import com.extendedae_plus.api.bridge.PatternProviderLogicAppfluxBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.mixin.appflux.accessor.PatternProviderLogicAppfluxAccessor;
import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.neoforged.fml.ModList;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -17,20 +18,13 @@ 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.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* 为样板供应器添加升级槽支持
* - 没有 AppliedFlux 添加 1 个升级槽
* - AppliedFlux 在其基础上再增加 1 总共 2
*
* 优先级 1100 确保在 AppliedFlux (默认优先级 1000) 之后执行
* appflux 存在时把它的样板供应器升级槽扩展到我们需要的槽位数
*/
@Mixin(value = PatternProviderLogic.class, priority = 1100, remap = false)
public abstract class PatternProviderLogicUpgradesMixin {
@Mixin(value = PatternProviderLogic.class, priority = 500, remap = false)
public abstract class PatternProviderLogicUpgradesMixin implements PatternProviderLogicAppfluxBridge {
@Final
@Shadow
@ -42,111 +36,74 @@ public abstract class PatternProviderLogicUpgradesMixin {
@Unique
private IUpgradeInventory eap$upgrades = UpgradeInventories.empty();
@Unique
private boolean eap$hasAppliedFlux = false;
@Unique
private boolean eap$upgradesInitialized = false;
@Inject(method = "<init>(Lappeng/api/networking/IManagedGridNode;Lappeng/helpers/patternprovider/PatternProviderLogicHost;I)V",
at = @At("TAIL"))
private void eap$initUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
try {
// 检测是否安装了 AppliedFlux
this.eap$hasAppliedFlux = ModList.get().isLoaded("appflux");
if (eap$hasAppliedFlux) {
// AppliedFlux 已安装尝试获取并扩展其升级槽
eap$extendAppliedFluxUpgrades();
} // 未安装 AppliedFlux 的情况由 CompatMixin 负责创建兼容升级槽
if (UpgradeSlotCompat.shouldListenToAppfluxUpgrades()) {
this.eap$ensureAppliedFluxUpgradeSlots();
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 初始化失败", t);
}
}
@Dynamic("AppFlux mixin adds IUpgradeableObject#getUpgrades to PatternProviderLogic")
@Inject(method = "getUpgrades", at = @At("RETURN"), cancellable = true, remap = false, require = 0)
private void eap$wrapAppfluxGetUpgrades(CallbackInfoReturnable<IUpgradeInventory> cir) {
if (!UpgradeSlotCompat.shouldListenToAppfluxUpgrades()) {
return;
}
IUpgradeInventory ensured = this.eap$ensureAppliedFluxUpgradeSlots(cir.getReturnValue());
if (ensured != null && ensured != cir.getReturnValue()) {
cir.setReturnValue(ensured);
}
}
@Override
public IUpgradeInventory eap$ensureAppfluxUpgradeSlots() {
return this.eap$ensureAppliedFluxUpgradeSlots();
}
@Unique
private void eap$extendAppliedFluxUpgrades() {
private IUpgradeInventory eap$ensureAppliedFluxUpgradeSlots() {
return this.eap$ensureAppliedFluxUpgradeSlots(null);
}
@Unique
private IUpgradeInventory eap$ensureAppliedFluxUpgradeSlots(IUpgradeInventory currentUpgrades) {
try {
// 通过反射直接读取 AppliedFlux Mixin 注入的字段af_upgrades
IUpgradeInventory existingUpgrades = null;
try {
Field f = this.getClass().getDeclaredField("af_upgrades");
f.setAccessible(true);
existingUpgrades = (IUpgradeInventory) f.get(this);
} catch (Throwable t) {
PatternProviderLogicAppfluxAccessor accessor = (PatternProviderLogicAppfluxAccessor) (Object) this;
IUpgradeInventory existingUpgrades = currentUpgrades != null ? currentUpgrades : accessor.eap$getAppfluxUpgrades();
int targetSlots = UpgradeSlotCompat.getPatternProviderAppfluxUpgradeSlots();
if (existingUpgrades != null && existingUpgrades.size() >= targetSlots) {
this.eap$upgrades = existingUpgrades;
return existingUpgrades;
}
if (existingUpgrades != null && existingUpgrades != UpgradeInventories.empty()) {
// AppliedFlux 已经创建了升级槽
int currentSlots = existingUpgrades.size();
int targetSlots = 2; // AppliedFlux 1个 + 我们 1个 = 2个
if (currentSlots < targetSlots) {
// 需要扩展升级槽
// 先保存现有物品
ItemStack[] savedItems = new ItemStack[currentSlots];
for (int i = 0; i < currentSlots; i++) {
savedItems[i] = existingUpgrades.getStackInSlot(i).copy();
}
// 创建新的升级槽更多槽位
this.eap$upgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
targetSlots,
this::eap$onUpgradesChanged
);
// 恢复原有物品
for (int i = 0; i < savedItems.length; i++) {
this.eap$upgrades.setItemDirect(i, savedItems[i]);
}
// AF 的字段指向我们新的升级槽保持其服务与 NBT 钩子一致
try {
Field f = this.getClass().getDeclaredField("af_upgrades");
f.setAccessible(true);
f.set(this, this.eap$upgrades);
} catch (Throwable t) {
}
this.eap$upgradesInitialized = true;
} else {
// AppliedFlux 或其他模组已经提供了足够的槽位
this.eap$upgrades = existingUpgrades;
this.eap$upgradesInitialized = true;
}
} else {
// AppliedFlux 还没初始化升级槽或者出了问题我们创建默认的
this.eap$upgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
2,
this.eap$upgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
targetSlots,
this::eap$onUpgradesChanged
);
// 同步 AF 字段
try {
Field f = this.getClass().getDeclaredField("af_upgrades");
f.setAccessible(true);
f.set(this, this.eap$upgrades);
} catch (Throwable t) {
);
if (existingUpgrades != null) {
for (int i = 0; i < Math.min(existingUpgrades.size(), this.eap$upgrades.size()); i++) {
ItemStack stack = existingUpgrades.getStackInSlot(i).copy();
if (!stack.isEmpty()) {
this.eap$upgrades.insertItem(i, stack, false);
}
}
this.eap$upgradesInitialized = true;
}
accessor.eap$setAppfluxUpgrades(this.eap$upgrades);
return this.eap$upgrades;
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 扩展 AppliedFlux 升级槽失败", t);
// 失败时创建默认数量
this.eap$upgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
2,
this::eap$onUpgradesChanged
);
// 同步 AF 字段最佳努力
try {
Field f = this.getClass().getDeclaredField("af_upgrades");
f.setAccessible(true);
f.set(this, this.eap$upgrades);
} catch (Throwable ignored) {}
this.eap$upgradesInitialized = true;
return currentUpgrades;
}
}
@ -154,116 +111,16 @@ public abstract class PatternProviderLogicUpgradesMixin {
private void eap$onUpgradesChanged() {
try {
this.host.saveChanges();
// 如果 AppliedFlux 安装了也调用其原始的 onUpgradesChanged 方法
if (eap$hasAppliedFlux) {
try {
Method afMethod = this.getClass().getDeclaredMethod("af_onUpgradesChanged");
afMethod.setAccessible(true);
afMethod.invoke(this);
} catch (NoSuchMethodException e) {
// AppliedFlux 的方法不存在这是正常的
} catch (Throwable t) {
}
try {
((PatternProviderLogicAppfluxAccessor) (Object) this).eap$invokeAppfluxUpgradesChanged();
return;
} catch (Throwable ignored) {
}
// 通过 Bridge 接口通知 CompatMixin 升级槽已变更
// 这样无论是否安装 AppFlux所有升级槽变更都会触发频道卡/虚拟合成卡的重新检测
if ((Object) this instanceof com.extendedae_plus.api.bridge.PatternProviderLogicUpgradeCompatBridge bridge) {
bridge.eap$onCompatUpgradesChangedHook();
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] onUpgradesChanged 处理失败", t);
}
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$saveUpgrades(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
try {
// 已安装 AF 时交由 AF mixin 处理避免重复写入
if (eap$hasAppliedFlux) {
return;
}
if (eap$upgradesInitialized && this.eap$upgrades != null && this.eap$upgrades != UpgradeInventories.empty()) {
// 根据是否有 AppliedFlux 使用不同的 NBT
if (eap$hasAppliedFlux) {
// AppliedFlux 使用 "upgrades" 我们使用 "eap_upgrades" 避免冲突
this.eap$upgrades.writeToNBT(tag, "eap_upgrades", registries);
} else {
// 没有 AppliedFlux使用标准键
this.eap$upgrades.writeToNBT(tag, "upgrades", registries);
}
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 保存升级槽失败", t);
}
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$loadUpgrades(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
try {
// 重新检测 AppliedFlux 状态可能在世界加载时状态有变化
this.eap$hasAppliedFlux = ModList.get().isLoaded("appflux");
if (!eap$upgradesInitialized) {
// 如果还没初始化先初始化
if (eap$hasAppliedFlux) {
eap$extendAppliedFluxUpgrades();
} else {
this.eap$upgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
1,
this::eap$onUpgradesChanged
);
this.eap$upgradesInitialized = true;
}
}
// 已安装 AF AF 自行从 "upgrades" 读取我们只处理无 AF 情况
if (!eap$hasAppliedFlux && this.eap$upgrades != null && this.eap$upgrades != UpgradeInventories.empty()) {
if (tag.contains("upgrades")) {
this.eap$upgrades.readFromNBT(tag, "upgrades", registries);
}
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 加载升级槽失败", t);
}
}
@Inject(method = "addDrops", at = @At("TAIL"))
private void eap$dropUpgrades(List<ItemStack> drops, CallbackInfo ci) {
try {
// AF 已安装时交由其自身处理掉落
if (eap$hasAppliedFlux) {
return;
}
if (eap$upgradesInitialized && this.eap$upgrades != null) {
for (var is : this.eap$upgrades) {
if (!is.isEmpty()) {
drops.add(is);
}
}
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 添加掉落失败", t);
}
}
@Inject(method = "clearContent", at = @At("TAIL"))
private void eap$clearUpgrades(CallbackInfo ci) {
try {
// AF 已安装时交由其自身处理清理
if (eap$hasAppliedFlux) {
return;
}
if (eap$upgradesInitialized && this.eap$upgrades != null) {
this.eap$upgrades.clear();
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器][升级槽] 清空升级槽失败", t);
}
}
}

View File

@ -7,6 +7,7 @@ import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.bridge.CompatUpgradeProvider;
import com.extendedae_plus.api.bridge.IUpgradableMenu;
import com.extendedae_plus.api.bridge.PatternProviderLogicAppfluxBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
@ -30,10 +31,20 @@ public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implem
super(menuType, id, playerInventory, host);
}
@Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V",
at = @At(value = "INVOKE", target = "Lappeng/menu/implementations/PatternProviderMenu;createPlayerInventorySlots(Lnet/minecraft/world/entity/player/Inventory;)V"),
remap = false)
private void eap$ensureAppfluxUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
if (UpgradeSlotCompat.shouldListenToAppfluxUpgrades()
&& (Object) this.logic instanceof PatternProviderLogicAppfluxBridge bridge) {
bridge.eap$ensureAppfluxUpgradeSlots();
}
}
@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()) {
if (UpgradeSlotCompat.shouldManageLocalUpgradeInventory()) {
this.eap$toolbox = new ToolboxMenu(this);
this.setupUpgrades(((CompatUpgradeProvider) this.logic).eap$getCompatUpgrades());
}

View File

@ -0,0 +1,19 @@
package com.extendedae_plus.mixin.appflux.accessor;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.helpers.patternprovider.PatternProviderLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(value = PatternProviderLogic.class, priority = 500, remap = false)
public interface PatternProviderLogicAppfluxAccessor {
@Accessor(value = "af_upgrades", remap = false)
IUpgradeInventory eap$getAppfluxUpgrades();
@Accessor(value = "af_upgrades", remap = false)
void eap$setAppfluxUpgrades(IUpgradeInventory upgrades);
@Invoker(value = "af_onUpgradesChanged", remap = false)
void eap$invokeAppfluxUpgradesChanged();
}

View File

@ -53,6 +53,7 @@
"ae2.parts.automation.IOBusPartChannelCardMixin",
"ae2.parts.storagebus.StorageBusPartChannelCardMixin",
"ae2WTlib.ContainerUWirelessExPatternTerminalMixin",
"appflux.accessor.PatternProviderLogicAppfluxAccessor",
"extendedae.accessor.TileAssemblerMatrixCrafterAccessor",
"extendedae.accessor.TileAssemblerMatrixPatternAccessor",
"extendedae.common.PartExPatternProviderMixin",