样板供应器

This commit is contained in:
GaLicn 2025-09-24 23:19:59 +08:00
parent 5cf2aa991f
commit aa0c26246b
8 changed files with 241 additions and 26 deletions

View File

@ -139,12 +139,12 @@ dependencies {
implementation "curse.maven:curios-309927:6529130"
compileOnly "curse.maven:ex-pattern-provider-892005:6863556"
implementation "curse.maven:applied-flux-965012:5614830"
compileOnly "curse.maven:applied-flux-965012:5614830"
compileOnly "dev.emi:emi-neoforge:1.1.10+1.21"
compileOnly "curse.maven:mega-cells-622112:6005043"
compileOnly "curse.maven:jade-324717:5427817"
compileOnly "me.shedaniel:RoughlyEnoughItems-neoforge:16.0.729"
// compileOnly "mekanism:Mekanism:1.21.1-10.7.0.55"
compileOnly "mekanism:Mekanism:1.21.1-10.7.0.55"
compileOnly "curse.maven:applied-mekanistics-574300:5978711"
compileOnly "dev.latvian.mods:kubejs-neoforge:2101.7.1-build.188"
compileOnly "dev.latvian.mods:rhino:2101.2.5-build.54"
@ -155,7 +155,7 @@ dependencies {
compileOnly "curse.maven:ae2-jei-integration-1074338:5748513"
// runtime test
runtimeOnly "curse.maven:applied-flux-965012:5614830"
//runtimeOnly "curse.maven:applied-flux-965012:5614830"
runtimeOnly "de.mari_023:ae2wtlib:19.2.1"
runtimeOnly "curse.maven:jade-324717:5427817"
runtimeOnly "curse.maven:mega-cells-622112:6005043"

View File

@ -0,0 +1,41 @@
package com.extendedae_plus.compat;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.widgets.UpgradesPanel;
import com.extendedae_plus.util.ExtendedAELogger;
/**
* AppliedFlux 兼容性处理工具类
* 用于检测和处理与AppliedFlux模组的UI冲突
*/
public final class AppliedFluxCompat {
private AppliedFluxCompat() {}
/**
* 检查PatternProviderScreen是否已经有AppliedFlux添加的升级面板
* 简化版本主要通过AppliedFlux模组加载状态来判断
*/
public static boolean hasAppliedFluxUpgradePanel(PatternProviderScreen<?> screen) {
// 如果AppliedFlux未加载肯定没有其升级面板
if (!UpgradeSlotCompat.shouldUseLowPriorityMode()) {
return false;
}
// 如果AppliedFlux加载了假设它会添加升级面板
// 这是一个保守的假设避免冲突
ExtendedAELogger.LOGGER.debug("[AppliedFlux兼容] 检测到AppliedFlux已加载假设存在升级面板");
return true;
}
/**
* 检查是否应该跳过添加我们的升级面板
*/
public static boolean shouldSkipOurUpgradePanel(PatternProviderScreen<?> screen) {
if (!UpgradeSlotCompat.shouldUseLowPriorityMode()) {
return false;
}
return hasAppliedFluxUpgradePanel(screen);
}
}

View File

@ -5,6 +5,7 @@ import net.neoforged.fml.ModList;
public final class UpgradeSlotCompat {
private static Boolean APPFLUX_LOADED;
private static Boolean APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE;
private UpgradeSlotCompat() {}
@ -20,6 +21,29 @@ public final class UpgradeSlotCompat {
return APPFLUX_LOADED;
}
/**
* 检测AppliedFlux的PatternProviderScreen mixin是否活跃
* 这比简单检查模组是否加载更准确
*/
private static boolean isAppfluxPatternProviderMixinActive() {
if (APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE == 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;
} catch (Throwable t) {
APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE = false;
}
}
return APPFLUX_PATTERN_PROVIDER_MIXIN_ACTIVE;
}
// 是否由我们提供升级槽当未安装 appflux
public static boolean shouldEnableUpgradeSlots() {
return !isAppfluxLoaded();
@ -30,9 +54,19 @@ public final class UpgradeSlotCompat {
return true;
}
// 客户端界面是否需要显示升级面板/不装 appflux 均显示
// appflux 提供的升级槽会以 SlotSemantics.UPGRADE 出现在菜单中我们只负责渲染面板
// 客户端界面是否需要显示升级面板
// 如果AppliedFlux的mixin活跃我们降低优先级让它处理
public static boolean shouldAddUpgradePanelToScreen() {
return true;
return true; // 总是尝试添加但在代码中检测冲突
}
// 是否应该使用低优先级模式当AppliedFlux存在时
public static boolean shouldUseLowPriorityMode() {
return isAppfluxPatternProviderMixinActive();
}
// 获取推荐的mixin优先级
public static int getRecommendedMixinPriority() {
return isAppfluxPatternProviderMixinActive() ? 1500 : 2000;
}
}

View File

@ -3,7 +3,11 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.api.upgrades.Upgrades;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.layout.SlotGridLayout;
import appeng.client.gui.style.Blitter;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.SlotPosition;
import appeng.client.gui.style.WidgetStyle;
import appeng.client.gui.widgets.ToolboxPanel;
import appeng.client.gui.widgets.UpgradesPanel;
import appeng.core.localization.GuiText;
@ -12,6 +16,8 @@ import appeng.menu.implementations.PatternProviderMenu;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.compat.AppliedFluxCompat;
import com.extendedae_plus.util.IStyleAccessor;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin;
@ -23,30 +29,70 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = PatternProviderScreen.class, priority = 2000, remap = false)
@Mixin(value = PatternProviderScreen.class, priority = 1500, remap = false)
public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
@Inject(method = "<init>", at = @At("TAIL"))
@Inject(method = "<init>", at = @At("TAIL"), remap = false)
private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 开始初始化升级面板");
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] shouldAddUpgradePanelToScreen: {}", UpgradeSlotCompat.shouldAddUpgradePanelToScreen());
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] shouldUseLowPriorityMode: {}", UpgradeSlotCompat.shouldUseLowPriorityMode());
if (!UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 跳过添加升级面板shouldAddUpgradePanelToScreen返回false");
return;
}
try {
this.widgets.add("upgrades", new UpgradesPanel(
menu.getSlots(SlotSemantics.UPGRADE),
this::eap$getCompatibleUpgrades));
} catch (IllegalStateException already) {
// 已存在同名面板可能由 AE2 或其他模组添加忽略
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 升级面板已存在,跳过添加");
}
if (menu instanceof AEBaseMenu base && base instanceof com.extendedae_plus.bridge.IUpgradableMenu upg && upg.getToolbox() != null && upg.getToolbox().isPresent()) {
// 使用改进的AppliedFlux兼容性检测
@SuppressWarnings("unchecked")
PatternProviderScreen<PatternProviderMenu> screen = (PatternProviderScreen<PatternProviderMenu>) (Object) this;
boolean shouldSkip = AppliedFluxCompat.shouldSkipOurUpgradePanel(screen);
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] AppliedFlux兼容性检测结果: shouldSkip={}", shouldSkip);
if (shouldSkip) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 检测到AppliedFlux升级面板跳过添加我们的面板");
} else {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 开始添加升级面板");
// 检查是否已经存在upgrades widget
try {
this.widgets.add("toolbox", new ToolboxPanel(style, upg.getToolbox().getName()));
} catch (IllegalStateException already) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 工具箱面板已存在,跳过添加");
// 尝试添加升级面板
this.widgets.add("upgrades", new UpgradesPanel(menu.getSlots(SlotSemantics.UPGRADE), this::eap$getCompatibleUpgrades));
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 成功添加升级面板");
} catch (IllegalStateException e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 升级面板已存在,跳过添加: {}", e.getMessage());
return; // 如果升级面板已存在不继续添加其他内容
}
// 设置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.bridge.IUpgradableMenu upg && upg.getToolbox() != null && upg.getToolbox().isPresent()) {
try {
this.widgets.add("toolbox", new ToolboxPanel(style, upg.getToolbox().getName()));
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 成功添加工具箱面板");
} catch (IllegalStateException e) {
com.extendedae_plus.util.ExtendedAELogger.LOGGER.warn("[样板供应器][界面] 工具箱面板已存在,跳过添加: {}", e.getMessage());
}
}
com.extendedae_plus.util.ExtendedAELogger.LOGGER.debug("[样板供应器][界面] 按照AppliedFlux方式完成升级面板和工具箱初始化");
}
}
@Unique
private List<Component> eap$getCompatibleUpgrades() {

View File

@ -0,0 +1,34 @@
package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.gui.style.Blitter;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.WidgetStyle;
import com.extendedae_plus.util.IStyleAccessor;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
@Mixin(ScreenStyle.class)
public abstract class ScreenStyleMixin implements IStyleAccessor {
@Final
@Shadow(remap = false)
private Map<String, Blitter> images;
@Final
@Shadow(remap = false)
private Map<String, WidgetStyle> widgets;
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public Map<String, Blitter> getImages() {
return this.images;
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Override
public Map<String, WidgetStyle> getWidgets() {
return this.widgets;
}
}

View File

@ -184,18 +184,49 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
boolean found = false;
IUpgradeInventory upgrades = null;
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
upgrades = this.eap$compatUpgrades;
ExtendedAELogger.LOGGER.debug("[样板供应器] 使用自带升级槽(未安装 appflux: {}", upgrades != null);
} else {
// appflux 应该注入其自身的 IUpgradeableObject 实现
// 优先尝试从AppliedFlux获取升级槽如果安装了的话
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 安装了appflux优先使用appflux的升级槽
try {
if ((Object) this instanceof IUpgradeableObject uo) {
upgrades = uo.getUpgrades();
ExtendedAELogger.LOGGER.debug("[样板供应器] 使用 appflux 提供的升级槽: {}", upgrades != null);
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 获取第三方升级槽失败", t);
ExtendedAELogger.LOGGER.error("[样板供应器] 获取 appflux 升级槽失败,回退到兼容槽", t);
// 如果获取AppliedFlux升级槽失败回退到我们的兼容槽
upgrades = this.eap$compatUpgrades;
}
} else {
// 未安装appflux使用我们的兼容升级槽
upgrades = this.eap$compatUpgrades;
ExtendedAELogger.LOGGER.debug("[样板供应器] 使用自带升级槽(未安装 appflux: {}", upgrades != null);
}
// 双重保险如果主要方式失败尝试备用方式
if (upgrades == null || eap$isUpgradeInventoryEmpty(upgrades)) {
ExtendedAELogger.LOGGER.debug("[样板供应器] 主升级槽为空,尝试备用方式");
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 如果我们的槽为空尝试检查是否有AppliedFlux的槽
try {
if ((Object) this instanceof IUpgradeableObject uo) {
IUpgradeInventory backupUpgrades = uo.getUpgrades();
if (backupUpgrades != null && !eap$isUpgradeInventoryEmpty(backupUpgrades)) {
upgrades = backupUpgrades;
ExtendedAELogger.LOGGER.debug("[样板供应器] 使用备用 appflux 升级槽");
}
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.debug("[样板供应器] 备用升级槽检查失败: {}", t.getMessage());
}
} else {
// 如果AppliedFlux的槽为空尝试我们的兼容槽
if (this.eap$compatUpgrades != null && !eap$isUpgradeInventoryEmpty(this.eap$compatUpgrades)) {
upgrades = this.eap$compatUpgrades;
ExtendedAELogger.LOGGER.debug("[样板供应器] 使用备用兼容升级槽");
}
}
}
@ -273,6 +304,19 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
}
// CompatUpgradeProvider 实现仅在未安装 appflux 时由我们提供升级槽
@Unique
private boolean eap$isUpgradeInventoryEmpty(IUpgradeInventory inventory) {
if (inventory == null) {
return true;
}
for (ItemStack stack : inventory) {
if (!stack.isEmpty()) {
return false;
}
}
return true;
}
@Override
public IUpgradeInventory eap$getCompatUpgrades() {
return this.eap$compatUpgrades != null ? this.eap$compatUpgrades : UpgradeInventories.empty();

View File

@ -0,0 +1,14 @@
package com.extendedae_plus.util;
import appeng.client.gui.style.Blitter;
import appeng.client.gui.style.WidgetStyle;
import java.util.Map;
public interface IStyleAccessor {
Map<String, Blitter> getImages();
Map<String, WidgetStyle> getWidgets();
}

View File

@ -63,6 +63,8 @@
"ae2.client.gui.PatternEncodingTermScreenMixin",
"ae2.client.gui.PatternProviderCloseMixin",
"ae2.client.gui.PatternProviderScreenMixin",
"ae2.client.gui.PatternProviderScreenUpgradesMixin",
"ae2.client.gui.ScreenStyleMixin",
"ae2.client.gui.SlotGridLayoutMixin",
"ae2.menu.CraftConfirmMenuGoBackMixin",
"extendedae.accessor.GuiExPatternTerminalAccessor",