1、添加虚拟合成卡对Neo ECO的适配(issue #61)
2、整理虚拟合成卡相关代码
This commit is contained in:
C-H716 2026-05-29 01:49:07 +08:00
parent 603d543038
commit 7dda653ebf
12 changed files with 443 additions and 225 deletions

View File

@ -132,7 +132,7 @@ configurations {
dependencies {
// --- Added dependencies for target mods ---
implementation "curse.maven:glodium-957920:5821676"
implementation "org.appliedenergistics:appliedenergistics2:19.2.15"
implementation "org.appliedenergistics:appliedenergistics2:19.2.17"
implementation "org.appliedenergistics:guideme:2.5.1"
// jarJar configuration not set in this build; use implementation for API for now
implementation "de.mari_023:ae2wtlib_api:19.2.0"
@ -172,6 +172,10 @@ dependencies {
//geckolib
runtimeOnly "curse.maven:geckolib-388172:7009924"
// eco
// runtimeOnly "curse.maven:ldlib-626676:8133369"
compileOnly "curse.maven:neo-eco-ae-extension-1460639:7884362"
//ftbteams
runtimeOnly "curse.maven:ftb-teams-forge-404468:6930910"
runtimeOnly "curse.maven:ftb-library-forge-404465:7029003"

View File

@ -18,7 +18,7 @@ minecraft_version=1.21.1
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21.1]
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.1.206
neo_version=21.1.216
# The loader version range can only use the major version of FML as bounds
loader_version_range=[1,)

View File

@ -42,6 +42,10 @@ public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
return isClassPresent("com.glodblock.github.appflux.AppFlux");
}
private static boolean isNeoECOAEPresent() {
return isClassPresent("cn.dancingsnow.neoecoae.NeoECOAE");
}
@Override
public void onLoad(String mixinPackage) { }
@ -63,6 +67,11 @@ public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
return false;
}
}
if (!isNeoECOAEPresent()) {
if (mixinClassName.startsWith("com.extendedae_plus.mixin.neoecoae.")) {
return false;
}
}
if (mixinClassName.equals("com.extendedae_plus.mixin.ae2.CraftingCPUClusterMixin")) {
if (isUfoPresent() || isBiggerAePresent()) {
return false;

View File

@ -2,7 +2,6 @@ package com.extendedae_plus.mixin.advancedae.compat;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingService;
import appeng.api.stacks.KeyCounter;
import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge;
@ -10,9 +9,9 @@ import com.extendedae_plus.mixin.advancedae.accessor.AdvCraftingCPUAccessor;
import com.extendedae_plus.mixin.advancedae.accessor.AdvCraftingCPULogicAccessor;
import com.extendedae_plus.mixin.advancedae.accessor.AdvExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.advancedae.accessor.AdvExecutingCraftingJobTaskProgressAccessor;
import com.extendedae_plus.util.VirtualCraftingHelper;
import net.pedroksl.advanced_ae.common.cluster.AdvCraftingCPU;
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.CallbackInfoReturnable;
@ -28,114 +27,54 @@ public abstract class PatternProviderLogicVirtualCompletionMixin {
@Inject(method = "pushPattern", at = @At("RETURN"))
private void eap$advancedaeVirtualCompletion(IPatternDetails patternDetails, KeyCounter[] inputHolder,
CallbackInfoReturnable<Boolean> cir) {
if (!cir.getReturnValueZ()) {
return;
}
if (!(this instanceof PatternProviderLogicVirtualCompatBridge bridge)) {
return;
}
if (!bridge.eap$compatIsVirtualCraftingEnabled()) {
if (!cir.getReturnValueZ()
|| !(this instanceof PatternProviderLogicVirtualCompatBridge bridge)
|| !bridge.eap$compatIsVirtualCraftingEnabled()) {
return;
}
var mainNode = bridge.eap$compatGetMainNode();
if (mainNode == null) {
return;
}
VirtualCraftingHelper.executeVirtualCompletion(
bridge.eap$compatGetMainNode(),
patternDetails,
new VirtualCraftingHelper.VirtualCompletionHandler<AdvCraftingCPU, AdvExecutingCraftingJobTaskProgressAccessor>() {
@Override
public boolean isValidCPU(ICraftingCPU cpu) {
return cpu instanceof AdvCraftingCPU;
}
var node = mainNode.getNode();
if (node == null) {
return;
}
var grid = node.getGrid();
if (grid == null) {
return;
}
ICraftingService craftingService = grid.getCraftingService();
if (craftingService == null) {
return;
}
for (ICraftingCPU cpu : craftingService.getCpus()) {
if (!cpu.isBusy()) {
continue;
}
if (cpu instanceof AdvCraftingCPU advCpu) {
var logic = advCpu.craftingLogic;
if (logic instanceof AdvCraftingCPULogicAccessor advLogicAccessor) {
var job = advLogicAccessor.eap$getAdvJob();
if (job != null && job instanceof AdvExecutingCraftingJobAccessor advJobAccessor) {
var tasks = advJobAccessor.eap$getAdvTasks();
var progress = tasks.get(patternDetails);
if (progress == null && patternDetails != null) {
var patternDefinition = patternDetails.getDefinition();
for (var entry : tasks.entrySet()) {
var taskPattern = entry.getKey();
if (taskPattern == patternDetails) {
progress = entry.getValue();
break;
}
if (taskPattern != null && patternDefinition != null) {
var taskDefinition = taskPattern.getDefinition();
if (taskDefinition != null && taskDefinition.equals(patternDefinition)) {
progress = entry.getValue();
break;
}
}
@Override
@SuppressWarnings("unchecked")
public Map<IPatternDetails, AdvExecutingCraftingJobTaskProgressAccessor> getTasks(
AdvCraftingCPU cpu) {
var logic = cpu.craftingLogic;
if (logic instanceof AdvCraftingCPULogicAccessor la) {
var job = la.eap$getAdvJob();
if (job instanceof AdvExecutingCraftingJobAccessor ja) {
return (Map<IPatternDetails, AdvExecutingCraftingJobTaskProgressAccessor>) (Map<?, ?>) ja.eap$getAdvTasks();
}
}
return null;
}
if (progress instanceof AdvExecutingCraftingJobTaskProgressAccessor advProgressAccessor) {
if (this.eap$advancedaeShouldCancelWholeJob(tasks, advProgressAccessor)) {
boolean finished = false;
try {
((AdvCraftingCPUAccessor) (Object) advCpu).eap$invokeUpdateOutput(null);
} catch (Throwable ignored) {
}
try {
advLogicAccessor.eap$invokeAdvFinishJob(true);
finished = true;
} catch (Throwable ignored) {
}
if (!finished) {
advCpu.cancelJob();
}
break;
@Override
public long getProgressValue(AdvExecutingCraftingJobTaskProgressAccessor progress) {
return progress.eap$getAdvValue();
}
@Override
public boolean finishJob(AdvCraftingCPU cpu) {
try {
((AdvCraftingCPUAccessor) cpu).eap$invokeUpdateOutput(null);
if (cpu.craftingLogic instanceof AdvCraftingCPULogicAccessor la) {
la.eap$invokeAdvFinishJob(true);
return true;
}
} catch (Throwable ignored) {
}
cpu.cancelJob();
return true;
}
}
}
}
}
@Unique
private boolean eap$advancedaeShouldCancelWholeJob(
Map<IPatternDetails, Object> tasks,
AdvExecutingCraftingJobTaskProgressAccessor matchedProgress) {
if (matchedProgress.eap$getAdvValue() > 1) {
return false;
}
for (var entry : tasks.entrySet()) {
var taskProgress = entry.getValue();
if (!(taskProgress instanceof AdvExecutingCraftingJobTaskProgressAccessor advTaskProgress)) {
continue;
}
long remaining = advTaskProgress.eap$getAdvValue();
if (taskProgress == matchedProgress) {
remaining -= 1;
}
if (remaining > 0) {
return false;
}
}
return true;
);
}
}

View File

@ -1,18 +1,14 @@
package com.extendedae_plus.mixin.ae2.compat;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IGridConnection;
import appeng.api.networking.IManagedGridNode;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.security.IActionSource;
import appeng.api.stacks.KeyCounter;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.api.upgrades.UpgradeInventories;
import appeng.blockentity.AEBaseBlockEntity;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.CompatUpgradeProvider;
@ -21,9 +17,6 @@ import com.extendedae_plus.api.bridge.PatternProviderLogicUpgradeCompatBridge;
import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCPUClusterAccessor;
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 com.extendedae_plus.util.wireless.ChannelCardLinkHelper;
@ -37,9 +30,6 @@ 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
import java.util.List;
import java.util.UUID;
@ -189,9 +179,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
}
}
@Override
public void eap$updateWirelessLink() {
if (this.eap$compatLink != null) {
@ -382,10 +369,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
private void eap$compatNotifyHostChanged() {
try {
this.host.saveChanges();
} catch (Throwable ignored) {
}
try {
if (this.host.getBlockEntity() instanceof AEBaseBlockEntity blockEntity) {
blockEntity.markForUpdate();
}
@ -430,84 +413,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
return this.eap$compatUpgrades != null ? this.eap$compatUpgrades : UpgradeInventories.empty();
}
@Inject(method = "pushPattern", at = @At("RETURN"), cancellable = true)
private void eap$compatAfterPushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder, CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) {
this.eap$compatTryVirtualCompletion(patternDetails);
}
}
@Unique
private void eap$compatTryVirtualCompletion(IPatternDetails patternDetails) {
if (!this.eap$compatVirtualCraftingEnabled) {
return;
}
var node = this.mainNode.getNode();
if (node == null) {
return;
}
var grid = node.getGrid();
if (grid == null) {
return;
}
var craftingService = grid.getCraftingService();
if (craftingService == null) {
return;
}
for (ICraftingCPU cpu : craftingService.getCpus()) {
if (!cpu.isBusy()) {
continue;
}
if (cpu instanceof CraftingCPUCluster cluster) {
if (cluster.craftingLogic instanceof CraftingCpuLogicAccessor logicAccessor) {
var job = logicAccessor.eap$getJob();
if (job instanceof ExecutingCraftingJobAccessor accessor) {
var tasks = accessor.eap$getTasks();
var progress = tasks.get(patternDetails);
if (progress == null && patternDetails != null) {
var patternDefinition = patternDetails.getDefinition();
for (var entry : tasks.entrySet()) {
var taskPattern = entry.getKey();
if (taskPattern == patternDetails) {
progress = entry.getValue();
break;
}
if (taskPattern != null && patternDefinition != null) {
var taskDefinition = taskPattern.getDefinition();
if (taskDefinition != null && taskDefinition.equals(patternDefinition)) {
progress = entry.getValue();
break;
}
}
}
}
if (this.eap$compatShouldCancelWholeJob(tasks, progress)) {
boolean finished = false;
try {
((CraftingCPUClusterAccessor) (Object) cluster).eap$invokeUpdateOutput(null);
} catch (Throwable ignored) {
}
try {
logicAccessor.eap$invokeFinishJob(true);
finished = true;
} catch (Throwable ignored) {
}
if (!finished) {
cluster.cancelJob();
}
break;
}
}
}
}
}
}
@Override
public boolean eap$compatIsVirtualCraftingEnabled() {
return this.eap$compatVirtualCraftingEnabled;
@ -518,33 +423,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
return this.mainNode;
}
@Unique
private boolean eap$compatShouldCancelWholeJob(
Map<IPatternDetails, com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobTaskProgressAccessor> tasks,
com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobTaskProgressAccessor matchedProgress) {
if (matchedProgress == null || matchedProgress.eap$getValue() > 1) {
return false;
}
for (var entry : tasks.entrySet()) {
var taskProgress = entry.getValue();
if (taskProgress == null) {
continue;
}
long remaining = taskProgress.eap$getValue();
if (taskProgress == matchedProgress) {
remaining -= 1;
}
if (remaining > 0) {
return false;
}
}
return true;
}
@Unique
private void eap$compatSyncVirtualCraftingState() {
try {

View File

@ -0,0 +1,77 @@
package com.extendedae_plus.mixin.ae2.compat;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.stacks.KeyCounter;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCPUClusterAccessor;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobTaskProgressAccessor;
import com.extendedae_plus.util.VirtualCraftingHelper;
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.CallbackInfoReturnable;
import java.util.Map;
/**
* AE2 版本的虚拟完成兼容逻辑
*/
@Mixin(value = PatternProviderLogic.class, priority = 900, remap = false)
public abstract class PatternProviderLogicVirtualCompletionMixin {
@Inject(method = "pushPattern", at = @At("RETURN"))
private void eap$ae2VirtualCompletion(IPatternDetails patternDetails, KeyCounter[] inputHolder,
CallbackInfoReturnable<Boolean> cir) {
if (!cir.getReturnValueZ() || !(this instanceof PatternProviderLogicVirtualCompatBridge bridge)
|| !bridge.eap$compatIsVirtualCraftingEnabled()) {
return;
}
VirtualCraftingHelper.executeVirtualCompletion(
bridge.eap$compatGetMainNode(),
patternDetails,
new VirtualCraftingHelper.VirtualCompletionHandler<CraftingCPUCluster, ExecutingCraftingJobTaskProgressAccessor>() {
@Override
public boolean isValidCPU(ICraftingCPU cpu) {
return cpu instanceof CraftingCPUCluster;
}
@Override
public Map<IPatternDetails, ExecutingCraftingJobTaskProgressAccessor> getTasks(CraftingCPUCluster cpu) {
var logic = cpu.craftingLogic;
if (logic instanceof CraftingCpuLogicAccessor la) {
var job = la.eap$getJob();
if (job instanceof ExecutingCraftingJobAccessor ja) {
return ja.eap$getTasks();
}
}
return null;
}
@Override
public long getProgressValue(ExecutingCraftingJobTaskProgressAccessor progress) {
return progress.eap$getValue();
}
@Override
public boolean finishJob(CraftingCPUCluster cpu) {
try {
((CraftingCPUClusterAccessor) (Object) cpu).eap$invokeUpdateOutput(null);
if (cpu.craftingLogic instanceof CraftingCpuLogicAccessor la) {
la.eap$invokeFinishJob(true);
return true;
}
} catch (Throwable ignored) {
}
cpu.cancelJob();
return true;
}
}
);
}
}

View File

@ -0,0 +1,16 @@
package com.extendedae_plus.mixin.neoecoae.accessor;
import cn.dancingsnow.neoecoae.api.me.ECOCraftingCPULogic;
import cn.dancingsnow.neoecoae.api.me.ExecutingCraftingJob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(value = ECOCraftingCPULogic.class, remap = false)
public interface ECOCraftingCPULogicAccessor {
@Accessor("job")
ExecutingCraftingJob eap$getECOJob();
@Invoker("finishJob")
void eap$invokeECOFinishJob(boolean success);
}

View File

@ -0,0 +1,15 @@
package com.extendedae_plus.mixin.neoecoae.accessor;
import appeng.api.crafting.IPatternDetails;
import cn.dancingsnow.neoecoae.api.me.ExecutingCraftingJob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(value = ExecutingCraftingJob.class, remap = false)
public interface ECOExecutingCraftingJobAccessor {
@Accessor("tasks")
Map<IPatternDetails, Object> eap$getECOTasks();
}

View File

@ -0,0 +1,10 @@
package com.extendedae_plus.mixin.neoecoae.accessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(targets = "cn.dancingsnow.neoecoae.api.me.ExecutingCraftingJob$TaskProgress", remap = false)
public interface ECOTaskProgressAccessor {
@Accessor("value")
long eap$getECOValue();
}

View File

@ -0,0 +1,78 @@
package com.extendedae_plus.mixin.neoecoae.compat;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.stacks.KeyCounter;
import appeng.helpers.patternprovider.PatternProviderLogic;
import cn.dancingsnow.neoecoae.api.me.ECOCraftingCPU;
import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge;
import com.extendedae_plus.mixin.neoecoae.accessor.ECOCraftingCPULogicAccessor;
import com.extendedae_plus.mixin.neoecoae.accessor.ECOExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.neoecoae.accessor.ECOTaskProgressAccessor;
import com.extendedae_plus.util.VirtualCraftingHelper;
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.CallbackInfoReturnable;
import java.util.Map;
/**
* NeoECOAE 版本的虚拟完成兼容逻辑
*/
@Mixin(value = PatternProviderLogic.class, priority = 840, remap = false)
public abstract class PatternProviderLogicVirtualCompletionMixin {
@Inject(method = "pushPattern", at = @At("RETURN"))
private void eap$neoecoaeVirtualCompletion(IPatternDetails patternDetails, KeyCounter[] inputHolder,
CallbackInfoReturnable<Boolean> cir) {
if (!cir.getReturnValueZ()
|| !(this instanceof PatternProviderLogicVirtualCompatBridge bridge)
|| !bridge.eap$compatIsVirtualCraftingEnabled()) {
return;
}
VirtualCraftingHelper.executeVirtualCompletion(
bridge.eap$compatGetMainNode(),
patternDetails,
new VirtualCraftingHelper.VirtualCompletionHandler<ECOCraftingCPU, ECOTaskProgressAccessor>() {
@Override
public boolean isValidCPU(ICraftingCPU cpu) {
return cpu instanceof ECOCraftingCPU;
}
@Override
@SuppressWarnings("unchecked")
public Map<IPatternDetails, ECOTaskProgressAccessor> getTasks(ECOCraftingCPU cpu) {
var logic = cpu.getLogic();
if (logic instanceof ECOCraftingCPULogicAccessor la) {
var job = la.eap$getECOJob();
if (job instanceof ECOExecutingCraftingJobAccessor ja) {
return (Map<IPatternDetails, ECOTaskProgressAccessor>) (Map<?, ?>) ja.eap$getECOTasks();
}
}
return null;
}
@Override
public long getProgressValue(ECOTaskProgressAccessor progress) {
return progress.eap$getECOValue();
}
@Override
public boolean finishJob(ECOCraftingCPU cpu) {
try {
var logic = cpu.getLogic();
if (logic instanceof ECOCraftingCPULogicAccessor la) {
la.eap$invokeECOFinishJob(true);
return true;
}
} catch (Throwable ignored) {
}
cpu.cancelJob();
return true;
}
}
);
}
}

View File

@ -0,0 +1,187 @@
package com.extendedae_plus.util;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IManagedGridNode;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingService;
import java.util.Map;
import java.util.function.Function;
/**
* 虚拟合成卡辅助工具类
* 用于处理不同MOD的CPU虚拟完成逻辑
*/
public class VirtualCraftingHelper {
/**
* 检查是否应该取消整个任务
*
* @param tasks 任务映射
* @param matchedProgress 匹配到的进度
* @param valueExtractor 提取进度的函数
* @return 是否应该取消整个任务
*/
public static <T> boolean shouldCancelWholeJob(
Map<IPatternDetails, T> tasks,
T matchedProgress,
Function<T, Long> valueExtractor) {
if (matchedProgress == null) {
return false;
}
long matchedValue = valueExtractor.apply(matchedProgress);
if (matchedValue > 1) {
return false;
}
for (var entry : tasks.entrySet()) {
var taskProgress = entry.getValue();
if (taskProgress == null) {
continue;
}
long remaining = valueExtractor.apply(taskProgress);
if (taskProgress == matchedProgress) {
remaining -= 1;
}
if (remaining > 0) {
return false;
}
}
return true;
}
/**
* 查找匹配的进度
*
* @param tasks 任务映射
* @param patternDetails 样板详情
* @return 匹配的进度如果没有则返回null
*/
public static <T> T findMatchingProgress(
Map<IPatternDetails, T> tasks,
IPatternDetails patternDetails) {
if (patternDetails == null) {
return null;
}
var progress = tasks.get(patternDetails);
if (progress != null) {
return progress;
}
var patternDefinition = patternDetails.getDefinition();
for (var entry : tasks.entrySet()) {
var taskPattern = entry.getKey();
if (taskPattern == patternDetails) {
return entry.getValue();
}
if (taskPattern != null && patternDefinition != null) {
var taskDefinition = taskPattern.getDefinition();
if (taskDefinition != null && taskDefinition.equals(patternDefinition)) {
return entry.getValue();
}
}
}
return null;
}
/**
* 获取网格的合成服务
*
* @param mainNode 主节点
* @return 合成服务如果不可用则返回null
*/
public static ICraftingService getCraftingService(IManagedGridNode mainNode) {
if (mainNode == null) {
return null;
}
var node = mainNode.getNode();
if (node == null) {
return null;
}
var grid = node.getGrid();
if (grid == null) {
return null;
}
return grid.getCraftingService();
}
/**
* 虚拟完成处理器接口
*/
public interface VirtualCompletionHandler<T extends ICraftingCPU, P> {
/**
* 检查CPU类型是否匹配
*/
boolean isValidCPU(ICraftingCPU cpu);
/**
* 获取任务映射
*/
Map<IPatternDetails, P> getTasks(T cpu);
/**
* 获取进度值
*/
long getProgressValue(P progress);
/**
* 完成任务
* @return 是否成功完成
*/
boolean finishJob(T cpu);
}
/**
* 执行虚拟完成逻辑
*
* @param mainNode 主节点
* @param patternDetails 样板详情
* @param handler 处理器
*/
@SuppressWarnings("unchecked")
public static <T extends ICraftingCPU, P> void executeVirtualCompletion(
IManagedGridNode mainNode,
IPatternDetails patternDetails,
VirtualCompletionHandler<T, P> handler) {
ICraftingService craftingService = getCraftingService(mainNode);
if (craftingService == null) {
return;
}
for (ICraftingCPU cpu : craftingService.getCpus()) {
if (!cpu.isBusy()) {
continue;
}
if (!handler.isValidCPU(cpu)) {
continue;
}
T typedCpu = (T) cpu;
Map<IPatternDetails, P> tasks = handler.getTasks(typedCpu);
if (tasks == null) {
continue;
}
P progress = findMatchingProgress(tasks, patternDetails);
if (progress == null) {
continue;
}
if (shouldCancelWholeJob(tasks, progress, handler::getProgressValue)) {
if (handler.finishJob(typedCpu)) {
break;
}
}
}
}
}

View File

@ -39,6 +39,7 @@
"ae2.autopattern.CraftingSimulationStateMixin",
"ae2.autopattern.PatternProviderLogicContainsRedirectMixin",
"ae2.compat.PatternProviderLogicCompatMixin",
"ae2.compat.PatternProviderLogicVirtualCompletionMixin",
"ae2.helpers.InterfaceLogicChannelCardMixin",
"ae2.helpers.InterfaceLogicTickerMixin",
"ae2.helpers.InterfaceLogicUpgradesMixin",
@ -71,7 +72,11 @@
"extendedae.container.ContainerExPatternProviderMixin",
"extendedae.container.ContainerExPatternTerminalMixin",
"extendedae.container.ContainerWirelessExPatternTerminalMixin",
"minecraft.accessor.BlockEntityAccessor"
"minecraft.accessor.BlockEntityAccessor",
"neoecoae.accessor.ECOCraftingCPULogicAccessor",
"neoecoae.accessor.ECOExecutingCraftingJobAccessor",
"neoecoae.accessor.ECOTaskProgressAccessor",
"neoecoae.compat.PatternProviderLogicVirtualCompletionMixin"
],
"client": [
"accessor.AbstractContainerScreenAccessor",