兼容applied flux

This commit is contained in:
GaLicn 2025-09-23 17:43:38 +08:00
parent a8b9b8e749
commit 428f4520b2
14 changed files with 921 additions and 10 deletions

View File

@ -81,7 +81,7 @@ dependencies {
annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor"
modImplementation "curse.maven:applied-flux-965012:6755986"
// modImplementation "curse.maven:applied-flux-965012:6755986"
modCompileOnly "curse.maven:mega-cells-622112:${mega_cells_version}"
modCompileOnly "curse.maven:jade-324717:${jade_version}"

View File

@ -4,6 +4,7 @@ import appeng.api.storage.StorageCells;
import appeng.menu.locator.MenuLocators;
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler;
import com.extendedae_plus.client.ClientRegistrar;
import com.extendedae_plus.compat.CompatibilityTest;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.init.*;
import com.extendedae_plus.menu.locator.CuriosItemLocator;
@ -62,6 +63,9 @@ public class ExtendedAEPlus {
private void commonSetup(final FMLCommonSetupEvent event) {
StorageCells.addCellHandler(InfinityBigIntegerCellHandler.INSTANCE);
// 运行兼容性测试
CompatibilityTest.testCompatibility();
// 注册本模组网络通道与数据包
event.enqueueWork(() -> {
// 注册升级卡

View File

@ -0,0 +1,62 @@
package com.extendedae_plus.compat;
import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraftforge.fml.ModList;
/**
* 兼容性测试类
* 用于验证模组兼容性检测是否正常工作
*/
public class CompatibilityTest {
/**
* 测试模组兼容性检测
*/
public static void testCompatibility() {
ExtendedAELogger.LOGGER.info("=== ExtendedAE_Plus 兼容性测试开始 ===");
// 测试appflux模组检测
boolean appfluxExists = ModList.get().isLoaded("appflux");
ExtendedAELogger.LOGGER.info("ExtendedAE-appflux模组检测结果: {}", appfluxExists ? "存在" : "不存在");
// 测试升级卡槽功能启用状态
boolean shouldEnableUpgrades = UpgradeSlotCompat.shouldEnableUpgradeSlots();
ExtendedAELogger.LOGGER.info("升级卡槽功能启用状态: {}", shouldEnableUpgrades ? "启用" : "禁用");
// 测试Screen升级面板添加状态
boolean shouldAddPanel = UpgradeSlotCompat.shouldAddUpgradePanelToScreen();
ExtendedAELogger.LOGGER.info("Screen升级面板添加状态: {}", shouldAddPanel ? "启用" : "禁用");
// 输出兼容性策略
if (appfluxExists) {
ExtendedAELogger.LOGGER.info("兼容性策略: 检测到ExtendedAE-appflux模组将使用其升级卡槽功能");
} else {
ExtendedAELogger.LOGGER.info("兼容性策略: 未检测到ExtendedAE-appflux模组将使用我们自己的升级卡槽功能");
}
ExtendedAELogger.LOGGER.info("=== ExtendedAE_Plus 兼容性测试完成 ===");
}
/**
* 获取兼容性状态报告
*/
public static String getCompatibilityReport() {
boolean appfluxExists = ModList.get().isLoaded("appflux");
boolean upgradesEnabled = UpgradeSlotCompat.shouldEnableUpgradeSlots();
StringBuilder report = new StringBuilder();
report.append("ExtendedAE_Plus 兼容性报告:\n");
report.append("- ExtendedAE-appflux模组: ").append(appfluxExists ? "已安装" : "未安装").append("\n");
report.append("- 升级卡槽功能: ").append(upgradesEnabled ? "启用中" : "已禁用").append("\n");
if (appfluxExists && !upgradesEnabled) {
report.append("- 兼容性状态: 正常 (使用appflux的升级功能)\n");
} else if (!appfluxExists && upgradesEnabled) {
report.append("- 兼容性状态: 正常 (使用我们的升级功能)\n");
} else {
report.append("- 兼容性状态: 异常 (配置不一致)\n");
}
return report.toString();
}
}

View File

@ -0,0 +1,202 @@
package com.extendedae_plus.compat;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.api.upgrades.UpgradeInventories;
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.ExtendedAELogger;
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模组是否存在如果存在则使用其升级卡槽功能
* 否则使用我们自己的实现
*/
public class UpgradeSlotCompat {
private static final String APPFLUX_MOD_ID = "appflux";
/**
* 检测是否应该启用我们的升级卡槽功能
* @return true如果应该启用false如果检测到appflux模组存在
*/
public static boolean shouldEnableUpgradeSlots() {
boolean appfluxExists = ModList.get().isLoaded(APPFLUX_MOD_ID);
ExtendedAELogger.LOGGER.info("ExtendedAE-appflux模组检测: {}", appfluxExists ? "存在" : "不存在");
if (appfluxExists) {
ExtendedAELogger.LOGGER.info("检测到ExtendedAE-appflux模组跳过我们的升级卡槽功能");
return false;
} else {
ExtendedAELogger.LOGGER.info("未检测到ExtendedAE-appflux模组启用我们的升级卡槽功能");
return true;
}
}
/**
* 检测是否应该在Screen中添加升级面板
* @return true如果应该添加false如果检测到appflux模组存在
*/
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) {
ExtendedAELogger.LOGGER.error("反射调用setupUpgrades失败", e);
return false;
}
// 使用反射或接口设置工具箱
if (menu instanceof IUpgradeableMenuCompat compatMenu) {
compatMenu.setCompatToolbox(toolbox);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderMenu初始化升级功能");
return true;
}
} catch (Exception e) {
ExtendedAELogger.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);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderScreen添加升级面板");
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);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderScreen添加升级面板使用put方法");
return true;
} catch (Exception e2) {
ExtendedAELogger.LOGGER.error("反射调用widgets方法失败", e2);
return false;
}
}
}
} catch (Exception e) {
ExtendedAELogger.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) {
ExtendedAELogger.LOGGER.error("获取兼容升级列表时出错", e);
}
return list;
}
/**
* 兼容性升级菜单接口
*/
public interface IUpgradeableMenuCompat {
ToolboxMenu getCompatToolbox();
void setCompatToolbox(ToolboxMenu toolbox);
IUpgradeInventory getCompatUpgrades();
}
}

View File

@ -0,0 +1,79 @@
package com.extendedae_plus.mixin;
import net.minecraftforge.fml.ModList;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.List;
import java.util.Set;
/**
* Mixin条件加载插件
* 用于根据模组存在情况动态加载不同的Mixin
*/
public class MixinConditions implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
// 初始化时调用
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
// 对于升级相关的Mixin检查appflux是否存在
if (mixinClassName.contains("PatternProviderMenuUpgradesMixin") ||
mixinClassName.contains("PatternProviderScreenUpgradesMixin") ||
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);
return shouldApply;
} catch (Exception e) {
System.out.println("[ExtendedAE_Plus] ModList检查失败默认应用升级Mixin: " + mixinClassName);
return true; // 修改策略出错时默认应用运行时再检查
}
}
// 其他Mixin正常应用
System.out.println("[ExtendedAE_Plus] 加载Mixin: " + mixinClassName);
return true;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
// 接受目标类
}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
// 应用前调用
}
@Override
public void postApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
// 应用后调用
}
}

View File

@ -10,6 +10,7 @@ import appeng.core.localization.GuiText;
import appeng.menu.SlotSemantics;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.IUpgradableMenu;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin;
@ -21,15 +22,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = PatternProviderScreen.class, remap = false)
@Mixin(value = PatternProviderScreen.class, priority = 2000, remap = false)
public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
@Inject(method = "<init>", at = @At("TAIL"))
private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 只有在应该启用升级卡槽时才添加升级面板
if (!UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) {
return;
}
this.widgets.add("upgrades", new UpgradesPanel(
menu.getSlots(SlotSemantics.UPGRADE),
this::eap$getCompatibleUpgrades));
if (((IUpgradableMenu) menu).getToolbox().isPresent()) {
if (((IUpgradableMenu) menu).getToolbox() != null && ((IUpgradableMenu) menu).getToolbox().isPresent()) {
this.widgets.add("toolbox", new ToolboxPanel(style, ((IUpgradableMenu) menu).getToolbox().getName()));
}
}

View File

@ -0,0 +1,69 @@
package com.extendedae_plus.mixin.ae2.compat;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu;
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;
/**
* PatternProviderMenu的兼容性Mixin
* 优先级设置为500低于appflux的默认优先级避免冲突
*/
@Mixin(value = PatternProviderMenu.class, priority = 500, remap = false)
public abstract class PatternProviderCompatMixin extends AEBaseMenu implements UpgradeSlotCompat.IUpgradeableMenuCompat {
@Unique
private ToolboxMenu eap$compatToolbox;
@Unique
private IUpgradeInventory eap$compatUpgrades;
@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$initCompatUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
try {
// 检测是否应该启用升级卡槽功能
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 直接初始化升级功能
this.eap$compatToolbox = new ToolboxMenu(this);
if (host instanceof appeng.api.upgrades.IUpgradeableObject upgradeableHost) {
this.eap$compatUpgrades = upgradeableHost.getUpgrades();
this.setupUpgrades(this.eap$compatUpgrades);
}
}
} catch (Exception e) {
// 静默处理异常确保不会因为升级功能导致崩溃
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("PatternProviderMenu兼容性升级初始化失败", e);
}
}
@Override
public ToolboxMenu getCompatToolbox() {
return this.eap$compatToolbox;
}
@Override
public void setCompatToolbox(ToolboxMenu toolbox) {
this.eap$compatToolbox = toolbox;
}
@Override
public IUpgradeInventory getCompatUpgrades() {
return this.eap$compatUpgrades;
}
// 构造函数Mixin要求
public PatternProviderCompatMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
}

View File

@ -0,0 +1,337 @@
package com.extendedae_plus.mixin.ae2.compat;
import appeng.api.networking.IManagedGridNode;
import appeng.api.networking.security.IActionSource;
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.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
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;
import java.util.List;
/**
* PatternProviderLogic的兼容性Mixin
* 优先级设置为500避免与appflux冲突
*/
@Mixin(value = PatternProviderLogic.class, priority = 500, remap = false)
public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObject, InterfaceWirelessLinkBridge {
@Unique
private IUpgradeInventory eap$compatUpgrades = UpgradeInventories.empty();
@Unique
private WirelessSlaveLink eap$compatLink;
@Unique
private long eap$compatLastChannel = -1;
@Unique
private boolean eap$compatClientConnected = false;
@Unique
private boolean eap$compatHasInitialized = false;
@Unique
private int eap$compatDelayedInitTicks = 0;
@Final
@Shadow
private PatternProviderLogicHost host;
@Final
@Shadow
private IManagedGridNode mainNode;
@Final
@Shadow
private IActionSource actionSource;
@Unique
private void eap$compatOnUpgradesChanged() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
try {
this.host.saveChanges();
// 升级变更重置并尝试初始化
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级变更处理失败", e);
}
}
@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 {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
this.eap$compatUpgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
1,
this::eap$compatOnUpgradesChanged
);
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级初始化失败", e);
}
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$compatSaveUpgrades(CompoundTag tag, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
this.eap$compatUpgrades.writeToNBT(tag, "compat_upgrades");
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级保存失败", e);
}
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$compatLoadUpgrades(CompoundTag tag, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
this.eap$compatUpgrades.readFromNBT(tag, "compat_upgrades");
// NBT 加载后重置并尝试初始化
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级加载失败", e);
}
}
@Inject(method = "addDrops", at = @At("TAIL"))
private void eap$compatDropUpgrades(List<ItemStack> drops, CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
for (var stack : this.eap$compatUpgrades) {
if (!stack.isEmpty()) {
drops.add(stack);
}
}
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级掉落失败", e);
}
}
@Inject(method = "clearContent", at = @At("TAIL"))
private void eap$compatClearUpgrades(CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
this.eap$compatUpgrades.clear();
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性升级清理失败", e);
}
}
@Override
public IUpgradeInventory getUpgrades() {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return this.eap$compatUpgrades;
}
return UpgradeInventories.empty();
}
@Override
public void eap$updateWirelessLink() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
try {
if (eap$compatLink != null) {
eap$compatLink.updateStatus();
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性无线链接更新失败", e);
}
}
@Unique
public void eap$compatInitializeChannelLink() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
try {
// 客户端早退
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
return;
}
// 避免重复初始化
if (eap$compatHasInitialized) {
return;
}
// 等待网格完成引导
if (!mainNode.hasGridBooted()) {
eap$compatDelayedInitTicks = Math.max(eap$compatDelayedInitTicks, 5);
try {
mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
});
} catch (Throwable ignored) {}
return;
}
long channel = 0L;
boolean found = false;
for (ItemStack stack : this.eap$compatUpgrades) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
channel = ChannelCardItem.getChannel(stack);
found = true;
break;
}
}
if (!found) {
// 无频道卡断开并视为初始化完成
if (eap$compatLink != null) {
eap$compatLink.setFrequency(0L);
eap$compatLink.updateStatus();
}
eap$compatHasInitialized = true;
return;
}
if (eap$compatLink == null) {
var endpoint = new GenericNodeEndpointImpl(() -> host.getBlockEntity(), () -> this.mainNode.getNode());
eap$compatLink = new WirelessSlaveLink(endpoint);
}
eap$compatLink.setFrequency(channel);
eap$compatLink.updateStatus();
if (eap$compatLink.isConnected()) {
eap$compatHasInitialized = true;
} else {
eap$compatHasInitialized = false;
eap$compatDelayedInitTicks = Math.max(eap$compatDelayedInitTicks, 5);
try {
mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
});
} catch (Throwable ignored) {}
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性频道链接初始化失败", e);
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
eap$compatClientConnected = connected;
}
}
@Override
public boolean eap$isWirelessConnected() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return false;
}
try {
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
return eap$compatClientConnected;
} else {
return eap$compatLink != null && eap$compatLink.isConnected();
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("检查兼容性无线连接状态失败", e);
return false;
}
}
@Override
public boolean eap$hasTickInitialized() {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return eap$compatHasInitialized;
}
return true;
}
@Override
public void eap$setTickInitialized(boolean initialized) {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
eap$compatHasInitialized = initialized;
}
}
@Override
public void eap$handleDelayedInit() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
try {
// 仅服务端
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
return;
}
if (!eap$compatHasInitialized) {
if (!mainNode.hasGridBooted()) {
if (eap$compatDelayedInitTicks > 0) {
eap$compatDelayedInitTicks--;
}
if (eap$compatDelayedInitTicks == 0) {
eap$compatDelayedInitTicks = 5;
try {
mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
});
} catch (Throwable ignored) {}
}
} else {
eap$compatInitializeChannelLink();
}
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性延迟初始化失败", e);
}
}
@Inject(method = "onMainNodeStateChanged", at = @At("TAIL"))
private void eap$compatOnMainNodeStateChangedTail(CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
try {
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatDelayedInitTicks = 10;
try {
mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
});
} catch (Throwable ignored) {}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("兼容性主节点状态变更处理失败", e);
}
}
}

View File

@ -0,0 +1,27 @@
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()) {
return UpgradeInventories.empty();
}
return ((IUpgradeableObject) this.getLogic()).getUpgrades();
}
}

View File

@ -0,0 +1,88 @@
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.ToolboxPanel;
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 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> {
@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) {
// 静默处理异常确保不会因为升级功能导致崩溃
com.extendedae_plus.util.ExtendedAELogger.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));
// 添加工具箱面板如果菜单实现了兼容接口
if (menu instanceof UpgradeSlotCompat.IUpgradeableMenuCompat compatMenu) {
var toolbox = compatMenu.getCompatToolbox();
if (toolbox != null && toolbox.isPresent()) {
this.widgets.add("toolbox", new ToolboxPanel(style, toolbox.getName()));
}
}
} catch (Exception e) {
com.extendedae_plus.util.ExtendedAELogger.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) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.error("获取兼容升级列表失败", e);
}
return list;
}
// 构造函数Mixin要求
public PatternProviderScreenCompatMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
}

View File

@ -10,12 +10,15 @@ import org.spongepowered.asm.mixin.Shadow;
/**
* PatternProviderLogicHost 作为 IUpgradeableObject 的代理菜单可从 host 获取升级槽
*/
@Mixin(value = PatternProviderLogicHost.class, remap = false)
@Mixin(value = PatternProviderLogicHost.class, priority = 2000, remap = false)
public interface PatternProviderLogicHostUpgradesMixin extends IUpgradeableObject {
@Shadow PatternProviderLogic getLogic();
@Override
default IUpgradeInventory getUpgrades() {
if (!com.extendedae_plus.compat.UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return appeng.api.upgrades.UpgradeInventories.empty();
}
return ((IUpgradeableObject) this.getLogic()).getUpgrades();
}
}

View File

@ -8,6 +8,7 @@ import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
@ -29,7 +30,7 @@ import java.util.List;
* PatternProviderLogic 注入升级槽实现 IUpgradeableObject
* 仅负责升级槽的持久化/掉落/清空与初始化不改变原有逻辑
*/
@Mixin(value = PatternProviderLogic.class, remap = false)
@Mixin(value = PatternProviderLogic.class, priority = 2000, remap = false)
public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableObject, InterfaceWirelessLinkBridge {
@Unique
private IUpgradeInventory eap$upgrades = UpgradeInventories.empty();
@ -75,16 +76,27 @@ public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableO
@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) {
// 只有在应该启用升级卡槽时才初始化
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
this.eap$upgrades = UpgradeInventories.forMachine(host.getTerminalIcon().getItem(), 1, this::eap$onUpgradesChanged);
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$saveUpgrades(CompoundTag tag, CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
this.eap$upgrades.writeToNBT(tag, "upgrades");
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$loadUpgrades(CompoundTag tag, CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
this.eap$upgrades.readFromNBT(tag, "upgrades");
// NBT 加载后重置并尝试初始化可能刚进入世界
eap$lastChannel = -1;
@ -94,6 +106,9 @@ public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableO
@Inject(method = "addDrops", at = @At("TAIL"))
private void eap$dropUpgrades(List<ItemStack> drops, CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
for (var stack : this.eap$upgrades) {
if (!stack.isEmpty()) {
drops.add(stack);
@ -103,6 +118,9 @@ public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableO
@Inject(method = "clearContent", at = @At("TAIL"))
private void eap$clearUpgrades(CallbackInfo ci) {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return;
}
this.eap$upgrades.clear();
}
@ -115,6 +133,9 @@ public abstract class PatternProviderLogicUpgradesMixin implements IUpgradeableO
@Override
public IUpgradeInventory getUpgrades() {
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
return UpgradeInventories.empty();
}
return this.eap$upgrades;
}

View File

@ -8,6 +8,7 @@ import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.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;
@ -18,7 +19,7 @@ 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, remap = false)
@Mixin(value = PatternProviderMenu.class, priority = 2000, remap = false)
public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implements IUpgradableMenu {
@Final
@Shadow protected PatternProviderLogic logic;
@ -29,17 +30,28 @@ public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implem
@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();
}

View File

@ -20,7 +20,7 @@
"ae2.client.gui.PatternEncodingTermScreenMixin",
"ae2.client.gui.PatternProviderCloseMixin",
"ae2.client.gui.PatternProviderScreenMixin",
"ae2.client.gui.PatternProviderScreenUpgradesMixin",
"ae2.compat.PatternProviderScreenCompatMixin",
"ae2.client.gui.SlotGridLayoutMixin",
"ae2.menu.CraftConfirmMenuGoBackMixin",
"extendedae.accessor.GuiExPatternTerminalAccessor",
@ -63,9 +63,9 @@
"ae2.menu.PatternEncodingTermMenuMixin",
"ae2.menu.PatternProviderMenuAdvancedMixin",
"ae2.menu.PatternProviderMenuDoublingMixin",
"ae2.helpers.patternprovider.PatternProviderLogicUpgradesMixin",
"ae2.helpers.patternprovider.PatternProviderLogicHostUpgradesMixin",
"ae2.menu.PatternProviderMenuUpgradesMixin",
"ae2.compat.PatternProviderLogicCompatMixin",
"ae2.compat.PatternProviderLogicHostCompatMixin",
"ae2.compat.PatternProviderCompatMixin",
"ae2.helpers.patternprovider.PatternProviderLogicTickerMixin",
"ae2.parts.AEBasePartClientSyncMixin",
"ae2.parts.automation.IOBusPartChannelCardMixin",
@ -84,5 +84,6 @@
"injectors": {
"defaultRequire": 1
},
"plugin": "com.extendedae_plus.mixin.MixinConditions",
"priority": 1000
}