Compare commits

...

29 Commits

Author SHA1 Message Date
C-H716
27048e08bf fix: 吞噬盘appflux联动配方使用物品id避免出现找不到tag的问题 2025-11-17 22:50:56 +08:00
C-H716
5923000d3b 去掉未找到可用矩阵的提示,静默处理 2025-11-17 15:40:30 +08:00
C-H716
680a1ebfd4 gtl: 1.4.5 2025-11-17 14:56:55 +08:00
C-H716
28c5d0a8f4 fix: 并行处理器GuideME 2025-11-17 14:56:29 +08:00
C-H716
54e0d8459d Merge branch 'develop/fix' into develop/gtl_support
# Conflicts:
#	build.gradle
2025-11-17 14:18:11 +08:00
C-H716
2821f8d024 gtl:fix4 2025-11-11 13:12:17 +08:00
C-H716
55c58ff89f 智能倍增相关健全性处理 2025-11-11 13:11:24 +08:00
C-H716
eace9531ea 修复合成数量小于provider数量时会出现multiplier等于0的情况 2025-11-11 13:11:13 +08:00
C-H716
66e815f613 gtl:fix3 2025-11-07 21:59:13 +08:00
C-H716
5996882b72 Merge branch 'develop/fix' into develop/gtl_support
# Conflicts:
#	build.gradle
#	src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java
#	src/main/resources/assets/extendedae_plus/lang/en_us.json
#	src/main/resources/assets/extendedae_plus/lang/zh_cn.json
2025-11-07 21:52:31 +08:00
C-H716
342a9510d7 gtl:新版翻倍支持 2025-11-04 21:04:09 +08:00
C-H716
9f703d89dc gtl:合并fix 2025-11-04 20:41:40 +08:00
C-H716
a4905c2a3f Merge remote-tracking branch 'origin/develop/gtl_support' into develop/gtl_support
# Conflicts:
#	src/main/java/com/extendedae_plus/config/ModConfig.java
#	src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeNodeMixin.java
#	src/main/resources/assets/extendedae_plus/lang/en_us.json
2025-11-04 20:38:27 +08:00
C-H716
e6dd8381bd gtl:去除对样板总成的翻倍支持 2025-11-04 20:32:52 +08:00
C-H716
2cf457fde3 gtl:补回原分子操纵者上传限制 2025-11-04 20:32:52 +08:00
C-H716
0b1077a20e gtl:提示 2025-11-04 20:32:49 +08:00
C-H716
c9797d3f6c gtl:补回缺失内容 2025-11-04 20:32:03 +08:00
C-H716
9bbeb97b1b gtl:新core样板倍增支持 2025-11-04 20:31:22 +08:00
Savitor
573a63bab7 合并fix分支,抽离合成样板上传分子操纵工具类 2025-11-04 20:30:58 +08:00
Savitor
50d74cafb0 合并fix分支,抽离合成样板上传分子操纵工具类 2025-11-04 20:26:31 +08:00
C-H716
9c69bc9175 gtl:补回原分子操纵者上传限制 2025-11-01 01:23:59 +08:00
C-H716
81be9efab4 gtl:提示 2025-11-01 01:04:54 +08:00
C-H716
c106cf1be7 Merge remote-tracking branch 'origin/develop/fix' into develop/gtl_support
# Conflicts:
#	src/main/java/com/extendedae_plus/network/crafting/CraftingMonitorOpenProviderC2SPacket.java
#	src/main/resources/assets/extendedae_plus/lang/zh_cn.json
2025-11-01 01:01:32 +08:00
C-H716
05f14e8150 gtl:补回缺失内容 2025-11-01 00:13:33 +08:00
C-H716
71b7bca977 gtl:新core样板倍增支持 2025-11-01 00:13:13 +08:00
C-H716
c48f712c8b Merge remote-tracking branch 'origin/develop/gtl_support' into develop/gtl_support
# Conflicts:
#	src/main/resources/assets/extendedae_plus/lang/en_us.json
2025-10-31 23:13:40 +08:00
Savitor
d8d734bfaf 合并fix分支,抽离合成样板上传分子操纵工具类 2025-10-31 23:12:40 +08:00
C-H716
0db446b056
Merge pull request #29 from Savitor-SN/develop/gtl_support
合并fix分支,抽离合成样板上传分子操纵工具类
2025-10-31 00:05:41 +08:00
Savitor
2e230dcad6 合并fix分支,抽离合成样板上传分子操纵工具类 2025-10-29 00:56:44 +08:00
27 changed files with 691 additions and 36 deletions

View File

@ -70,6 +70,15 @@ repositories {
}
maven { url "https://repo.spongepowered.org/maven" }
maven { url "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/" }
maven { // Registrate
url = "https://maven.tterrag.com/"
content {
// need to be specific here due to version overlaps
includeGroup("com.jozufozu.flywheel")
includeGroup("com.tterrag.registrate")
includeGroup("com.simibubi.create")
}
}
}
dependencies {
@ -105,18 +114,45 @@ dependencies {
modImplementation "curse.maven:jade-324717:${jade_version}"
// GregTech
modCompileOnly "curse.maven:gregtechceu-modern-890405:${gregtech_version}"
modCompileOnly "curse.maven:ldlib-626676:${ldlib_version}"
modImplementation "curse.maven:gregtechceu-modern-890405:${gregtech_version}"
modImplementation "curse.maven:ldlib-626676:5775541"
modImplementation files('libs/gtlcore-1.2.2.4-fix8.jar')
modImplementation("dev:gtmthings-1.3.5.b")
modImplementation("dev:resourcefullib-forge-1.20.1-2.1.29")
modImplementation("dev:resourcefulconfig-forge-1.20.1-2.1.3")
modImplementation("dev:botarium-forge-1.20.1-2.3.4")
modImplementation("dev:ad_astra-forge-1.20.1-1.15.20")
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
implementation(include("io.github.llamalad7:mixinextras-forge:0.2.0"))
modImplementation("com.tterrag.registrate:Registrate:MC1.20-1.3.11")
modImplementation("curse.maven:kubejs-238086:5454840")
modImplementation("curse.maven:rhino-416294:6186971")
//curios
modImplementation "curse.maven:curios-309927:${curios_version}"
// Runtime test
modRuntimeOnly "curse.maven:curios-309927:${curios_version}"
modImplementation "curse.maven:jade-324717:5339264"
modRuntimeOnly "dev.architectury:architectury-forge:9.2.14"
modRuntimeOnly "curse.maven:cloth-config-348521:5729105"
//jec
modImplementation "curse.maven:just-enough-characters-250702:6680042"
modCompileOnly "curse.maven:just-enough-characters-250702:6680042"
//
modRuntimeOnly("dev:jecharacters-1.20.1-forge-4.5.11-dev-shadow")
//
modRuntimeOnly("curse.maven:cloth-config-348521:5729105")
modRuntimeOnly("curse.maven:IMBlocker-483760:6922546")
//mae2
// modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6827727"
modCompileOnly "curse.maven:modern-ae2-additions-1028068:6827727"
//aea
modImplementation "curse.maven:advancedae-1084104:6939473"
//geckolib
modRuntimeOnly "curse.maven:geckolib-388172:6920925"
@ -130,8 +166,10 @@ dependencies {
//ftbteams
modCompileOnly "curse.maven:ftb-teams-forge-404468:6130786"
modCompileOnly "curse.maven:ftb-library-forge-404465:6807424"
modCompileOnly "curse.maven:ftb-chunk-forge-314906:6431735"
modRuntimeOnly "curse.maven:ftb-teams-forge-404468:6130786"
modRuntimeOnly "curse.maven:ftb-library-forge-404465:6807424"
modRuntimeOnly "curse.maven:ftb-chunk-forge-314906:6431735"
}
compileJava {

View File

@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
loom.platform = forge
# Mod properties
mod_version = 1.4.4
mod_version = 1.4.5-gtl
maven_group = com.extendedae_plus
archives_name = extendedae_plus
@ -26,7 +26,7 @@ rei_version=12.0.622
cloth_config_version=9.0.94
projecte_version=4901949
appliede_version=5364294
gregtech_version=5369020
gregtech_version=5753724
ldlib_version=5394816
ie_version=5224387
mixin_version=0.8.4

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
libs/gtmthings-1.3.5.b.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -22,7 +22,7 @@
"item": "appflux:energy_processor"
},
"M": {
"tag": "forge:gems/redstone"
"item": "appflux:redstone_crystal"
}
},
"pattern": [

View File

@ -23,7 +23,7 @@
"item": "appflux:core_256k"
},
"M": {
"tag": "forge:ingots/sky_insulating_resin"
"item": "appflux:sky_harden_insulating_resin"
},
"O": {
"item": "extendedae_plus:oblivion_singularity"

View File

@ -132,6 +132,14 @@ public final class ModConfig {
@Configurable.ValueUpdateCallback(method = "onEntityTickerMultipliersUpdate")
public String[] entityTickerMultipliers = {};
@Configurable
@Configurable.Comment(value = {
"限制合成样板自动上传仅进入分子操纵者",
"开启后,合成样板将只自动上传到分子操纵者,不再上传至装配矩阵"
})
@Configurable.Synchronized
public boolean restrictCraftingPatternToMolecular = false;
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> pendingPowerTask;
private static final Object POWER_LOCK = new Object();

View File

@ -11,7 +11,6 @@ import com.extendedae_plus.items.BasicCoreItem;
import com.extendedae_plus.items.materials.EntitySpeedCardItem;
import com.extendedae_plus.util.ModCheckUtils;
import com.glodblock.github.appflux.common.AFItemAndBlock;
import com.glodblock.github.appflux.util.AFTags;
import com.glodblock.github.extendedae.common.EPPItemAndBlock;
import gripe._90.megacells.definition.MEGAItems;
import net.minecraft.data.PackOutput;
@ -289,7 +288,7 @@ public class CraftingRecipes extends RecipeProvider {
.pattern("MCM")
.pattern("EBE")
.pattern("MEM")
.define('M', AFTags.REDSTONE_GEM)
.define('M', AFItemAndBlock.REDSTONE_CRYSTAL)
.define('C', AFItemAndBlock.CORE_16k)
.define('E', AFItemAndBlock.ENERGY_PROCESSOR)
.defineNbt('B', base)
@ -315,7 +314,7 @@ public class CraftingRecipes extends RecipeProvider {
.pattern("MOM")
.pattern("CBC")
.pattern("MCM")
.define('M', AFTags.SKY_RESIN_INGOT)
.define('M', AFItemAndBlock.SKY_HARDEN_INSULATING_RESIN)
.define('O', ModItems.OBLIVION_SINGULARITY.get())
.define('C', AFItemAndBlock.CORE_256k)
.defineNbt('B', BasicCoreItem.energyStage(2))

View File

@ -0,0 +1,105 @@
package com.extendedae_plus.mixin.ae2.autopattern.gtceu;
import appeng.api.crafting.IPatternDetails;
import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.google.common.collect.BiMap;
import org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEPatternBufferPartMachine;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Pseudo
@Mixin(value = MEPatternBufferPartMachine.class, remap = false)
public class GTLCoreMEPatternBufferPartMachineMixin {
@Final
@Shadow
private BiMap<IPatternDetails, Integer> patternSlotMap;
// 设置样板总成是否翻倍
@Inject(method = "getAvailablePatterns", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;toList()Ljava/util/List;", shift = At.Shift.BEFORE))
private void beforeToList(CallbackInfoReturnable<List<IPatternDetails>> cir) {
if (patternSlotMap == null) return;
for (Map.Entry<IPatternDetails, Integer> entry : patternSlotMap.entrySet()) {
IPatternDetails key = entry.getKey();
if (key instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(true);
}
}
}
// 重定向containsKey检查
@Redirect(method = "pushPattern(Lappeng/api/crafting/IPatternDetails;[Lappeng/api/stacks/KeyCounter;)Z",
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;containsKey(Ljava/lang/Object;)Z"))
private boolean redirectContainsKey(BiMap<IPatternDetails, ?> detailsSlotMap, Object key) {
try {
// 如果key是ScaledProcessingPattern类型尝试用其原始pattern进行判断
if (key instanceof ScaledProcessingPattern scaled) {
IPatternDetails base = scaled.getOriginal();
if (base != null) {
// 避免递归重定向直接遍历keySet判断
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, base)) return true;
}
}
}
// 常规判断遍历keySet
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, key)) return true;
}
return false;
} catch (Throwable t) {
// 出现异常时回退到常规判断
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, key)) return true;
}
return false;
}
}
@Redirect(method = "pushPattern(Lappeng/api/crafting/IPatternDetails;[Lappeng/api/stacks/KeyCounter;)Z",
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;get(Ljava/lang/Object;)Ljava/lang/Object;"))
private Object redirectGet(BiMap<IPatternDetails, ?> detailsSlotMap, Object key) {
try {
// 如果是 ScaledProcessingPattern优先尝试其原始 pattern 对应的值
if (key instanceof ScaledProcessingPattern scaled) {
IPatternDetails base = scaled.getOriginal();
if (base != null) {
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), base)) {
return e.getValue();
}
}
}
}
// 常规查找遍历 entrySet 避免再次调用 BiMap.get 导致递归重定向
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), key)) {
return e.getValue();
}
}
return null;
} catch (Throwable t) {
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), key)) {
return e.getValue();
}
}
return null;
}
}
}

View File

@ -0,0 +1,105 @@
package com.extendedae_plus.mixin.ae2.autopattern.gtceu;
import appeng.api.crafting.IPatternDetails;
import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.google.common.collect.BiMap;
import com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Pseudo
@Mixin(value = MEPatternBufferPartMachine.class, remap = false)
public class MEPatternBufferPartMachineMixin {
@Shadow
@Final
private BiMap<IPatternDetails, Integer> detailsSlotMap;
// 设置样板总成是否翻倍
@Inject(method = "getAvailablePatterns", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;toList()Ljava/util/List;", shift = At.Shift.BEFORE))
private void beforeToList(CallbackInfoReturnable<List<IPatternDetails>> cir) {
if (detailsSlotMap == null) return;
for (Map.Entry<IPatternDetails, Integer> entry : detailsSlotMap.entrySet()) {
IPatternDetails key = entry.getKey();
if (key instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(true);
}
}
}
// 重定向containsKey检查
@Redirect(method = "pushPattern(Lappeng/api/crafting/IPatternDetails;[Lappeng/api/stacks/KeyCounter;)Z",
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;containsKey(Ljava/lang/Object;)Z"))
private boolean redirectContainsKey(BiMap<IPatternDetails, ?> detailsSlotMap, Object key) {
try {
// 如果key是ScaledProcessingPattern类型尝试用其原始pattern进行判断
if (key instanceof ScaledProcessingPattern scaled) {
IPatternDetails base = scaled.getOriginal();
if (base != null) {
// 避免递归重定向直接遍历keySet判断
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, base)) return true;
}
}
}
// 常规判断遍历keySet
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, key)) return true;
}
return false;
} catch (Throwable t) {
// 出现异常时回退到常规判断
for (IPatternDetails d : detailsSlotMap.keySet()) {
if (Objects.equals(d, key)) return true;
}
return false;
}
}
@Redirect(method = "pushPattern(Lappeng/api/crafting/IPatternDetails;[Lappeng/api/stacks/KeyCounter;)Z",
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;get(Ljava/lang/Object;)Ljava/lang/Object;"))
private Object redirectGet(BiMap<IPatternDetails, ?> detailsSlotMap, Object key) {
try {
// 如果是 ScaledProcessingPattern优先尝试其原始 pattern 对应的值
if (key instanceof ScaledProcessingPattern scaled) {
IPatternDetails base = scaled.getOriginal();
if (base != null) {
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), base)) {
return e.getValue();
}
}
}
}
// 常规查找遍历 entrySet 避免再次调用 BiMap.get 导致递归重定向
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), key)) {
return e.getValue();
}
}
return null;
} catch (Throwable t) {
for (Map.Entry<IPatternDetails, ?> e : detailsSlotMap.entrySet()) {
if (Objects.equals(e.getKey(), key)) {
return e.getValue();
}
}
return null;
}
}
}

View File

@ -4,6 +4,8 @@ import appeng.api.crafting.PatternDetailsHelper;
import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.RestrictedInputSlot;
import appeng.parts.encoding.EncodingMode;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.util.uploadPattern.GTMatrixUploadUtil;
import com.extendedae_plus.util.uploadPattern.MatrixUploadUtil;
import com.glodblock.github.glodium.network.packet.sync.IActionHolder;
import com.glodblock.github.glodium.network.packet.sync.Paras;
@ -47,7 +49,9 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
}
var stack = this.encodedPatternSlot != null ? this.encodedPatternSlot.getItem() : net.minecraft.world.item.ItemStack.EMPTY;
if (stack != null && !stack.isEmpty() && PatternDetailsHelper.isEncodedPattern(stack)) {
MatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
if (!ModConfig.INSTANCE.restrictCraftingPatternToMolecular)
MatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
else GTMatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
} else {
// 槽位可能尚未同步到位继续下一 tick 重试
if (attemptsLeft > 0) {
@ -105,7 +109,9 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
// 为避免与 AE2 后续同步竞争切到下一 tick 执行
sp.server.execute(() -> {
try {
MatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
if (!ModConfig.INSTANCE.restrictCraftingPatternToMolecular)
MatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
else GTMatrixUploadUtil.uploadFromEncodingMenuToMatrix(sp, menu);
} catch (Throwable ignored) {
}
});
@ -117,7 +123,9 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
private void onEncodePatternReturn(CallbackInfoReturnable<ItemStack> cir) {
ItemStack itemStack = cir.getReturnValue();
if (itemStack != null && !itemStack.isEmpty()) {
itemStack.getOrCreateTag().putString("encodePlayer", this.epp$player.getGameProfile().getName());
itemStack.getOrCreateTag()
.putString("encodePlayer", this.epp$player.getGameProfile()
.getName());
cir.setReturnValue(itemStack);
}
}

View File

@ -0,0 +1,54 @@
package com.extendedae_plus.mixin.gtceu;
import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.stacks.AEKey;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.extendedae_plus.util.GuiUtil;
import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEPatternViewSlotWidget;
import com.lowdragmc.lowdraglib.gui.widget.SlotWidget;
import com.lowdragmc.lowdraglib.utils.Position;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@OnlyIn(Dist.CLIENT)
@Mixin(value = AEPatternViewSlotWidget.class, remap = false)
public abstract class AEPatternViewSlotWidgetMixin {
/**
* AEPatternViewSlotWidget.drawBackgroundTexture(...) 尾部注入绘制数字逻辑
*/
@Inject(method = "drawBackgroundTexture", at = @At("TAIL"))
private void onDrawInBackgroundTail(GuiGraphics graphics, int mouseX, int mouseY, CallbackInfo ci) {
if (!AEPatternViewSlotWidget.class.isInstance(this)) return;
// this 强转为 SlotWidget目标类继承自 SlotWidget
SlotWidget self = (SlotWidget) (Object) this;
Slot handler = self.getHandler();
if (handler == null) return;
// 使用 getRealStack 来尊重 setItemHook 的渲染替换
ItemStack displayStack = self.getRealStack(handler.getItem());
if (displayStack == null || displayStack.isEmpty()) return;
ItemStack stack = handler.getItem();
Position pos = self.getPosition(); // 来自 Widget 的方法继承可用
try {
var details = PatternDetailsHelper.decodePattern(stack, Minecraft.getInstance().level, false);
if (details != null && details.getOutputs() != null && details.getOutputs().length > 0) {
AEKey key = details.getOutputs()[0].what();
if (key != null && ClientPatternHighlightStore.hasHighlight(key)) {
GuiUtil.drawSlotRainbowHighlight(graphics, pos.x + 1, pos.y + 1);
}
}
} catch (Throwable ignore) {
}
}
}

View File

@ -0,0 +1,19 @@
package com.extendedae_plus.mixin.gtceu;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.lowdragmc.lowdraglib.gui.modular.ModularUIGuiContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = ModularUIGuiContainer.class, remap = false)
public class ModularUIGuiContainerCloseMixin {
@Inject(method = "removed", at = @At("HEAD"))
private void onRemoved(CallbackInfo ci) {
try {
ClientPatternHighlightStore.clearAll();
} catch (Throwable ignored) {}
}
}

View File

@ -0,0 +1,61 @@
package com.extendedae_plus.mixin.gtceu;
import com.extendedae_plus.util.GuiUtil;
import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEPatternViewSlotWidget;
import com.lowdragmc.lowdraglib.gui.util.DrawerHelper;
import com.lowdragmc.lowdraglib.gui.widget.SlotWidget;
import com.lowdragmc.lowdraglib.utils.Position;
import com.lowdragmc.lowdraglib.utils.Size;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@OnlyIn(Dist.CLIENT)
@Mixin(value = SlotWidget.class, remap = false)
public abstract class SlotWidgetMixin {
/**
* SlotWidget.drawInBackground(...) 尾部注入绘制数字逻辑
*/
@Inject(method = "drawInBackground(Lnet/minecraft/client/gui/GuiGraphics;IIF)V", at = @At("TAIL"))
private void onDrawInBackgroundTail(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks, CallbackInfo ci) {
if (!AEPatternViewSlotWidget.class.isInstance(this)) return;
// this 强转为 SlotWidget目标类继承自 SlotWidget
SlotWidget self = (SlotWidget) (Object) this;
Slot handler = self.getHandler();
if (handler == null) return;
// 使用 getRealStack 来尊重 setItemHook 的渲染替换
ItemStack displayStack = self.getRealStack(handler.getItem());
if (displayStack == null || displayStack.isEmpty()) return;
ItemStack stack = handler.getItem();
String patternOutputText = GuiUtil.getPatternOutputText(stack);
Position pos = self.getPosition(); // 来自 Widget 的方法继承可用
Size size = self.getSize(); // 同上
graphics.pose().pushPose();
graphics.pose().translate(0.0F, 0.0F, 300.0F);
RenderSystem.disableDepthTest();
DrawerHelper.drawStringFixedCorner(
graphics,
patternOutputText,
pos.x + size.width,
pos.y + size.height,
0xFFFFFFFF,
true,
0.75f);
RenderSystem.enableDepthTest();
graphics.pose().popPose();
}
}

View File

@ -16,10 +16,15 @@ import com.extendedae_plus.network.SetBlockHighlightS2CPacket;
import com.extendedae_plus.network.SetPatternHighlightS2CPacket;
import com.extendedae_plus.network.provider.SetProviderPageS2CPacket;
import com.extendedae_plus.util.PatternProviderDataUtil;
import com.glodblock.github.extendedae.client.render.EAEHighlightHandler;
import com.glodblock.github.glodium.util.GlodUtil;
import com.gregtechceu.gtceu.api.gui.factory.MachineUIFactory;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent;
@ -70,12 +75,23 @@ public class CraftingMonitorOpenProviderC2SPacket {
// 遍历所有样板找到第一个可用 Provider 并打开 UI
for (var pattern : patterns) {
var provider = PatternLocator.findValidProvider(craftingService, pattern, grid);
if (provider == null) continue;
var provider = CraftingMonitorOpenProviderC2SPacket.PatternLocator.findValidProvider(craftingService, pattern, grid);
if (provider == null) {
for (var pd : craftingService.getProviders(pattern)) {
if (pd instanceof com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine machine) {
gtmOpenUI(machine, player, pattern);
return;
} else if (pd instanceof org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEPatternBufferPartMachine machine) {
gtmOpenUI(machine, player, pattern);
return;
}
}
}
try {
ProviderUIHelper.openProviderUI(provider, pattern, player);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
});
context.setPacketHandled(true);
@ -83,6 +99,44 @@ public class CraftingMonitorOpenProviderC2SPacket {
// ===================== 内部工具类 =====================
/**
* 兼容gtm
*
* @param machine 样板总成
* @param player 玩家
* @param pattern 样板
*/
private static void gtmOpenUI(MetaMachine machine, ServerPlayer player, IPatternDetails pattern) {
try {
BlockPos pos = machine.getPos();
Level level = machine.getLevel();
if (pos == null || level == null) return;
if (!level.isClientSide) { // 确保在服务器端执行
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
}
// 聊天提示
player.displayClientMessage(
Component.translatable(
"chat.extendedae_plus.terminal.pos",
pos.toShortString(),
level.dimension().location().getPath(),
(int) Math.sqrt(player.blockPosition().distSqr(pos))
),
false
);
// 最后发送高亮包保证界面已打开
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
AEKey key = pattern.getOutputs()[0].what();
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
}
EAEHighlightHandler.highlight(pos, level.dimension(), System.currentTimeMillis() + 15000);
} catch (Exception ignored) {
}
}
/**
* GridHelper: 从菜单中获取网格实例
*/
@ -91,6 +145,7 @@ public class CraftingMonitorOpenProviderC2SPacket {
/**
* 获取菜单对应的 Grid
*
* @param menu 当前 AEBaseMenu
* @return Grid null
*/
@ -111,9 +166,10 @@ public class CraftingMonitorOpenProviderC2SPacket {
/**
* 查找提供指定样板的可用 Provider
* @param cs CraftingService
*
* @param cs CraftingService
* @param pattern 样板
* @param grid 当前 Grid
* @param grid 当前 Grid
* @return 第一个可用的 PatternProviderLogic null
*/
private static PatternProviderLogic findValidProvider(CraftingService cs, IPatternDetails pattern, IGrid grid) {
@ -144,8 +200,8 @@ public class CraftingMonitorOpenProviderC2SPacket {
* 4. 发送 Pattern 输出高亮包
*
* @param provider PatternProviderLogic 实例
* @param pattern 样板
* @param player 玩家
* @param pattern 样板
* @param player 玩家
*/
private static void openProviderUI(PatternProviderLogic provider, IPatternDetails pattern, ServerPlayer player) {
var host = ((PatternProviderLogicAccessor) provider).eap$host();

View File

@ -0,0 +1,179 @@
package com.extendedae_plus.util.uploadPattern;
import appeng.api.crafting.IPatternDetails;
import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.inventories.InternalInventory;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import appeng.core.definitions.AEItems;
import appeng.crafting.pattern.AECraftingPattern;
import appeng.crafting.pattern.AESmithingTablePattern;
import appeng.crafting.pattern.AEStonecuttingPattern;
import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.RestrictedInputSlot;
import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEMolecularAssemblerIOPartMachine;
import org.gtlcore.gtlcore.integration.ae2.AEUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage;
/**
* gtlcore 分子操纵者样板上传
* 用于从 AE2 的样板编码终端上传至分子操纵者仅合成样板
*/
public final class GTMatrixUploadUtil {
private GTMatrixUploadUtil() {
}
/**
* AE2 的样板编码终端菜单上传当前已编码合成样板 gtlcore 分子操纵者仅合成样板
*
* @param player 服务器玩家
* @param menu PatternEncodingTermMenu
*/
public static void uploadFromEncodingMenuToMatrix(ServerPlayer player, PatternEncodingTermMenu menu) {
if (player == null || menu == null) return;
// 读取已编码槽位的物品
RestrictedInputSlot encodedSlot = ((PatternEncodingTermMenuAccessor) menu).eap$getEncodedPatternSlot();
ItemStack stack = encodedSlot.getItem();
if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) return;
// 仅允许合成/锻造台/切石机样板
IPatternDetails details = PatternDetailsHelper.decodePattern(stack, player.level());
if (!(details instanceof AECraftingPattern
|| details instanceof AESmithingTablePattern
|| details instanceof AEStonecuttingPattern)) {
return;
}
if (!AEUtils.molecularFilter(stack, player.level())){
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 分子操纵者不支持该类型样板"));
refundBlankPattern(player, menu, stack.getCount());
return;
}
// 获取 AE 网络
IGridNode node = menu.getNetworkNode();
if (node == null) return;
IGrid grid = node.getGrid();
if (grid == null) return;
int stackCount = stack.getCount();
ItemStack toInsert = stack.copy();
// 收集所有可用的装配矩阵图样模块内部库存并逐一尝试遵循其过滤规则
List<InternalInventory> inventories = findAllGTMatrixPatternInventories(grid);
// 在尝试上传之前检查装配矩阵是否已经存在相同样板物品与NBT完全一致
if (GTMatrixContainsPattern(inventories, stack)) {
// 直接提醒并跳过上传并将同等数量的空白样板放回空白样板槽否则退回玩家背包
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_GTMatrix.repetition"));
refundBlankPattern(player, menu, stackCount);
encodedSlot.set(ItemStack.EMPTY);
return;
}
// 尝试插入
for (InternalInventory inv : inventories) {
if (inv == null) continue;
ItemStack remain = inv.addItems(toInsert);
if (remain.getCount() < stackCount) {
completeUploadSuccess(player, encodedSlot, stack, remain);
return;
}
}
// 未找到可用矩阵或全部拒收
sendPlayerMessage(player,
inventories.isEmpty()
? Component.translatable("extendedae_plus.upload_to_matrix.fail_no_GTMatrix")
: Component.translatable("extendedae_plus.upload_to_GTMatrix.fail_full"));
}
/**
* 在给定 AE Grid 中收集在线的GT分子的用于外部插入的内部库存
*/
private static List<InternalInventory> findAllGTMatrixPatternInventories(IGrid grid) {
List<InternalInventory> result = new ArrayList<>();
if (grid == null) return result;
try {
// 获取网络中所有 Pattern Tile
Set<MEMolecularAssemblerIOPartMachine> allTiles = grid.getMachines(MEMolecularAssemblerIOPartMachine.class);
for (MEMolecularAssemblerIOPartMachine tile : allTiles) {
if (tile == null || !tile.isFormed() || !tile.getMainNode()
.isActive()) continue;
InternalInventory inv = tile.getTerminalPatternInventory();
if (inv != null) {
result.add(inv);
}
}
} catch (Throwable ignored) {
}
return result;
}
/**
* 检查GT分子装配矩阵中是否已存在与给定样板完全相同的物品含NBT
*/
// todo
private static boolean GTMatrixContainsPattern(@NotNull List<InternalInventory> inventories, @NotNull ItemStack pattern) {
for (InternalInventory inv : inventories) {
if (inv == null) continue;
for (int i = 0; i < inv.size(); i++) {
ItemStack s = inv.getStackInSlot(i);
if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) {
return true;
}
}
}
return false;
}
/**
* 上传成功后处理清空编码槽发送提示
*/
private static void completeUploadSuccess(ServerPlayer player, RestrictedInputSlot encodedSlot, ItemStack stack, ItemStack remain) {
int inserted = stack.getCount() - remain.getCount();
if (inserted > 0) {
stack.shrink(inserted);
if (stack.isEmpty()) encodedSlot.set(ItemStack.EMPTY);
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_GTMatrix.success"));
}
}
/**
* 当发现重复样板时返还空白样板
*/
private static void refundBlankPattern(ServerPlayer player, PatternEncodingTermMenu menu, int count) {
try {
var accessor = (PatternEncodingTermMenuAccessor) menu;
var blankSlot = accessor.eap$getBlankPatternSlot();
ItemStack blanks = AEItems.BLANK_PATTERN.stack(count);
if (blankSlot != null && blankSlot.mayPlace(blanks)) {
ItemStack remain = blankSlot.safeInsert(blanks);
if (!remain.isEmpty() && player != null) {
player.getInventory()
.placeItemBackInInventory(remain, false);
}
} else if (player != null) {
player.getInventory()
.placeItemBackInInventory(blanks, false);
}
} catch (Throwable t) {
if (player != null) {
player.getInventory()
.placeItemBackInInventory(AEItems.BLANK_PATTERN.stack(count), false);
}
}
}
}

View File

@ -85,12 +85,6 @@ public final class MatrixUploadUtil {
return;
}
}
// 未找到可用矩阵或全部拒收
sendPlayerMessage(player,
inventories.isEmpty()
? Component.translatable("extendedae_plus.upload_to_matrix.fail_no_matrix")
: Component.translatable("extendedae_plus.upload_to_matrix.fail_full"));
}
/**

View File

@ -28,16 +28,16 @@ item_ids:
## 合成配方
### 4x并行处理单元
<Recipe id="extendedae_plus:4x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/4x_crafting_accelerator" />
### 16x并行处理单元
<Recipe id="extendedae_plus:16x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/16x_crafting_accelerator" />
### 64x并行处理单元
<Recipe id="extendedae_plus:64x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/64x_crafting_accelerator" />
### 256x并行处理单元
<Recipe id="extendedae_plus:256x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/256x_crafting_accelerator" />
### 1024x并行处理单元
<Recipe id="extendedae_plus:1024x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/1024x_crafting_accelerator" />

View File

@ -29,16 +29,16 @@ This mod introduces five higher-tier **Parallel Processing Units**, which are co
## Crafting Recipes
### 4x Parallel Processing Unit
<Recipe id="extendedae_plus:4x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/4x_crafting_accelerator" />
### 16x Parallel Processing Unit
<Recipe id="extendedae_plus:16x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/16x_crafting_accelerator" />
### 64x Parallel Processing Unit
<Recipe id="extendedae_plus:64x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/64x_crafting_accelerator" />
### 256x Parallel Processing Unit
<Recipe id="extendedae_plus:256x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/256x_crafting_accelerator" />
### 1024x Parallel Processing Unit
<Recipe id="extendedae_plus:1024x_crafting_accelerator" />
<Recipe id="extendedae_plus:network/crafting/1024x_crafting_accelerator" />

View File

@ -70,13 +70,30 @@
"extendedae_plus.upload_to_matrix": "Upload to Assembly Matrix",
"extendedae_plus.upload_to_matrix.success": "Pattern uploaded to the assembly matrix",
"extendedae_plus.upload_to_GTMatrix.success": "The template has been uploaded to the molecular manipulator",
"extendedae_plus.upload_to_matrix.fail_not_crafting": "Only crafting patterns are supported; processing patterns will be ignored",
"extendedae_plus.upload_to_matrix.fail_no_matrix": "No formed assembly matrix found in the current network",
"extendedae_plus.upload_to_matrix.fail_no_GTMatrix": "No formed molecular manipulators were found in the current network",
"extendedae_plus.upload_to_matrix.fail_full": "The assembly matrix pattern inventory is full or cannot insert",
"extendedae_plus.upload_to_GTMatrix.fail_full": "The Molecular Manipulator's pattern inventory is full or cannot accept the pattern",
"extendedae_plus.upload_to_matrix.repetition": "The Assembly Matrix already contains the same pattern, upload skipped and blank pattern returned",
"extendedae_plus.upload_to_GTMatrix.repetition": "The Molecular Manipulator already contains the same pattern, upload skipped and blank pattern returned",
"extendedae_plus.upload_to_GTMatrix.fail_full": "The sample compartment of the molecular manipulator is full or cannot be inserted",
"extendedae_plus.upload_to_matrix.repetition": "The assembly matrix already exists on the same board, and the upload is skipped and a blank template is returned",
"extendedae_plus.upload_to_GTMatrix.repetition": "The same board already exists for the molecular manipulator, skipping the upload and returning the blank template",
"extendedae_plus.upload_to_matrix.repetition": "The Assembly Matrix already contains the same pattern. Upload skipped and blank pattern returned.",
"chat.extendedae_plus.terminal.pos": "The crafting plan's corresponding provider is now highlighted at: %s, Dimension: %s (%s blocks away)",
"extendedae_plus.upload_to_GTMatrix.fail_full": "The sample compartment of the molecular manipulator is full or cannot be inserted",
"extendedae_plus.upload_to_matrix.repetition": "The assembly matrix already exists on the same board, and the upload is skipped and a blank template is returned",
"extendedae_plus.upload_to_GTMatrix.repetition": "The same board already exists for the molecular manipulator, skipping the upload and returning the blank template",
"extendedae_plus.upload_to_GTMatrix.fail_full": "The Molecular Manipulator's pattern inventory is full or cannot accept the pattern",
"extendedae_plus.upload_to_matrix.repetition": "The Assembly Matrix already contains the same pattern, upload skipped and blank pattern returned",
"extendedae_plus.upload_to_GTMatrix.repetition": "The Molecular Manipulator already contains the same pattern, upload skipped and blank pattern returned",
"extendedae_plus.gui.advanced_blocking.title": "Smart Blocking",
"extendedae_plus.gui.advanced_blocking.enabled_desc": "Will not block the same recipe type (requires vanilla blocking mode enabled)",
"extendedae_plus.gui.advanced_blocking.disabled_desc": "Use vanilla blocking logic",
@ -142,6 +159,7 @@
"config.extendedae_plus.option.entityTickerMultipliers": "Entity Ticker Extra Consumption Multipliers",
"config.extendedae_plus.option.craftingPauseThreshold": "AE synthesis calculation pause check threshold",
"config.extendedae_plus.option.prioritizeDiskEnergy": "Prioritize FE energy from disk (requires Applied Flux)",
"config.extendedae_plus.option.restrictCraftingPatternToMolecular": "Restrict automatic upload of synthetic templates to only molecular manipulators",
"item.extendedae_plus.channel_card": "Channel Card",
"item.extendedae_plus.channel_card.channel": "Frequency: %s",

View File

@ -70,12 +70,17 @@
"extendedae_plus.upload_to_matrix": "上传到装配矩阵",
"extendedae_plus.upload_to_matrix.success": "样板已上传到装配矩阵",
"extendedae_plus.upload_to_GTMatrix.success": "样板已上传到分子操纵者",
"extendedae_plus.upload_to_matrix.fail_not_crafting": "仅支持上传合成样板,处理样板将被忽略",
"extendedae_plus.upload_to_matrix.fail_no_matrix": "未在当前网络中找到已成型的装配矩阵",
"extendedae_plus.upload_to_matrix.fail_no_GTMatrix": "未在当前网络中找到已成型的分子操纵者",
"extendedae_plus.upload_to_matrix.fail_full": "装配矩阵的样板仓已满或无法插入",
"extendedae_plus.upload_to_GTMatrix.fail_full": "分子操纵者的样板仓已满或无法插入",
"extendedae_plus.upload_to_matrix.repetition": "装配矩阵已存在相同样板,已跳过上传并返还空白样板",
"extendedae_plus.upload_to_GTMatrix.repetition": "分子操纵者已存在相同样板,已跳过上传并返还空白样板",
"chat.extendedae_plus.terminal.pos": "合成计划对应供应器现在突出显示在:%s维度%s (%s个方块外)",
"extendedae_plus.upload_to_GTMatrix.repetition": "分子操纵者已存在相同样板,已跳过上传并返还空白样板",
"extendedae_plus.gui.advanced_blocking.title": "智能阻挡",
"extendedae_plus.gui.advanced_blocking.enabled_desc": "对于同一种配方将不再阻挡 (需要启用原版阻挡模式)",
@ -142,6 +147,7 @@
"config.extendedae_plus.option.entityTickerMultipliers": "实体加速器额外消耗倍率",
"config.extendedae_plus.option.prioritizeDiskEnergy": "优先从磁盘提取FE能量仅当Applied Flux模组存在时生效",
"config.extendedae_plus.option.craftingPauseThreshold": "AE合成计算暂停检查阈值",
"config.extendedae_plus.option.restrictCraftingPatternToMolecular": "限制合成样板自动上传仅进入分子操纵者",
"item.extendedae_plus.channel_card": "频道卡",
"item.extendedae_plus.channel_card.channel": "频率:%s",

View File

@ -27,6 +27,9 @@
"extendedae.client.HighlightButtonMixin",
"extendedae.client.gui.GuiExPatternProviderMixin",
"extendedae.client.gui.GuiExPatternTerminalMixin",
"gtceu.AEPatternViewSlotWidgetMixin",
"gtceu.ModularUIGuiContainerCloseMixin",
"gtceu.SlotWidgetMixin",
"jei.EncodePatternTransferHandlerMixin",
"jei.EncodingHelperMixin",
"jei.accessor.BookmarkOverlayAccessor",
@ -56,6 +59,8 @@
"ae2.autopattern.CraftingSimulationStateAccessor",
"ae2.autopattern.CraftingSimulationStateMixin",
"ae2.autopattern.PatternProviderLogicContainsRedirectMixin",
"ae2.autopattern.gtceu.GTLCoreMEPatternBufferPartMachineMixin",
"ae2.autopattern.gtceu.MEPatternBufferPartMachineMixin",
"ae2.compat.PatternProviderCompatMixin",
"ae2.compat.PatternProviderLogicCompatMixin",
"ae2.compat.PatternProviderLogicHostCompatMixin",