修复ScaledProcessingPattern未按照实际请求量缩放

This commit is contained in:
C-H716 2025-08-29 13:35:11 +08:00
parent 9c20608926
commit 692ffb7396
9 changed files with 155 additions and 36 deletions

View File

@ -103,7 +103,7 @@ dependencies {
modCompileOnly "curse.maven:just-enough-characters-250702:6680042"
//mae2
modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6342203"
// modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6342203"
modCompileOnly "curse.maven:modern-ae2-additions-1028068:6342203"
}

View File

@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
loom.platform = forge
# Mod properties
mod_version = 1.3.3
mod_version = 1.3.4-beta
maven_group = com.extendedae_plus
archives_name = extendedae_plus

View File

@ -20,7 +20,6 @@ public class CraftingServiceGetProvidersMixin {
IPatternDetails base = null;
if (original instanceof ScaledProcessingPattern scaledProcessingPattern) {
base = scaledProcessingPattern.getOriginal();
System.out.println("[extendedae_plus] CraftingService.getProviders mixin invoked for: " + base);
}
return base == null ? original : base;
}

View File

@ -0,0 +1,30 @@
package com.extendedae_plus.mixin.autopattern;
import appeng.api.stacks.KeyCounter;
import appeng.crafting.CraftingTreeNode;
import appeng.crafting.inv.CraftingSimulationState;
import com.extendedae_plus.util.RequestedAmountHolder;
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;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(value = CraftingTreeNode.class,remap = false)
public class CraftingTreeNodeMixin {
@Inject(method = "request(Lappeng/crafting/inv/CraftingSimulationState;JLappeng/api/stacks/KeyCounter;)V",
at = @At(value = "INVOKE",
target = "Lappeng/crafting/CraftingTreeNode;addContainerItems(Lappeng/api/stacks/AEKey;JLappeng/api/stacks/KeyCounter;)V"),
locals = LocalCapture.CAPTURE_FAILHARD)
private void captureRequestedAmount(CraftingSimulationState inv, long requestedAmount, KeyCounter containerItems, CallbackInfo ci) {
// push the requestedAmount before addContainerItems is called
RequestedAmountHolder.push(requestedAmount);
}
@Inject(method = "request(Lappeng/crafting/inv/CraftingSimulationState;JLappeng/api/stacks/KeyCounter;)V",
at = @At(value = "RETURN"))
private void clearRequestedAmountOnReturn(CraftingSimulationState inv, long requestedAmount, KeyCounter containerItems, CallbackInfo ci) {
// pop the pushed requested amount on return
RequestedAmountHolder.pop();
}
}

View File

@ -1,34 +1,52 @@
package com.extendedae_plus.mixin.autopattern;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.crafting.ICraftingService;
import appeng.api.stacks.AEKey;
import appeng.crafting.CraftBranchFailure;
import appeng.crafting.CraftingCalculation;
import appeng.crafting.CraftingTreeNode;
import appeng.crafting.CraftingTreeProcess;
import appeng.crafting.inv.CraftingSimulationState;
import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.util.PatternScaler;
import com.extendedae_plus.util.RequestedAmountHolder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
/**
* 注入 CraftingTreeProcess 构造器尾部 AEProcessingPattern 替换为 ScaledProcessingPattern
* 以确保后续执行使用放大后的输入/输出视图
*/
@Mixin(CraftingTreeProcess.class)
public class CraftingTreeProcessMixin {
public abstract class CraftingTreeProcessMixin {
// @ModifyVariable(method = "<init>(Lappeng/api/networking/crafting/ICraftingService;Lappeng/crafting/CraftingCalculation;Lappeng/api/crafting/IPatternDetails;Lappeng/crafting/CraftingTreeNode;)V",
// at = @At("HEAD"), argsOnly = true)
// private static IPatternDetails extendedae_plus$replaceDetailsAtHead(IPatternDetails original, ICraftingService cc, CraftingCalculation job, IPatternDetails details, CraftingTreeNode craftingTreeNode) {
// try {
// if (!(details instanceof AEProcessingPattern proc)) return original;
//
// CraftingCalculationAccessor jobAcc = (CraftingCalculationAccessor) job;
// long requested = jobAcc.extendedae_plus$getRequestedAmount();
//
// CraftingTreeNodeAccessor parentAcc = (CraftingTreeNodeAccessor) craftingTreeNode;
// AEKey parentTarget = parentAcc.extendedae_plus$getWhat();
//
// System.out.println("[extendedae_plus] Replacing constructor details at HEAD for: " + parentTarget + " x " + requested);
//
// return PatternScaler.scale(proc, parentTarget, requested);
// } catch (Exception e) {
// System.err.println("[extendedae_plus] Error replacing pattern at HEAD: " + e.getMessage());
// e.printStackTrace();
// return original;
// }
// }
@Shadow abstract void request(CraftingSimulationState inv, long times) throws CraftBranchFailure, InterruptedException;
@ModifyVariable(
method = "<init>(Lappeng/api/networking/crafting/ICraftingService;Lappeng/crafting/CraftingCalculation;Lappeng/api/crafting/IPatternDetails;Lappeng/crafting/CraftingTreeNode;)V",
at = @At("HEAD"),
argsOnly = true
)
private static IPatternDetails extendedae_plus$replaceDetailsAtHead(IPatternDetails original, ICraftingService cc, CraftingCalculation job, IPatternDetails details, CraftingTreeNode craftingTreeNode) {
try {
if (!(details instanceof AEProcessingPattern proc)) return original;
CraftingTreeNodeAccessor parentAcc = (CraftingTreeNodeAccessor) craftingTreeNode;
AEKey parentTarget = parentAcc.extendedae_plus$getWhat();
long requested = RequestedAmountHolder.get();
// 记录所使用的请求数量和当前线程堆栈快照便于诊断 PatternScaler.scale 使用了哪个值以及何时清理
LOGGER.info("[extendedae_plus] 在 CraftingTreeProcess 构造中使用请求数量: {} ; stackDepth={} ; stackSnapshot={}", requested, RequestedAmountHolder.depth(), RequestedAmountHolder.snapshot());
// 使用当前线程栈顶的值进行缩放不在此处清理构造完成后应该由调用方的 pop 恢复状态
return PatternScaler.scale(proc, parentTarget, requested);
} catch (Exception e) {
LOGGER.warn("构建倍增样板出错", e);
e.printStackTrace();
return original;
}
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.mixin.ae2;
package com.extendedae_plus.mixin.autopattern;
import appeng.api.crafting.IPatternDetails;
import appeng.helpers.patternprovider.PatternProviderLogic;
@ -26,7 +26,6 @@ public class PatternProviderLogicContainsRedirectMixin {
if (o instanceof ScaledProcessingPattern scaled) {
IPatternDetails base = scaled.getOriginal();
if (base != null && list.indexOf(base) != -1) {
System.out.println("[extendedae_plus] contains-redirect: matched base pattern for scaled pattern");
return true;
}
}

View File

@ -8,6 +8,8 @@ import com.extendedae_plus.content.ScaledProcessingPattern;
import java.util.Arrays;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
public final class PatternScaler {
private PatternScaler() {
}
@ -103,14 +105,13 @@ public final class PatternScaler {
/* Debug 输出 */
System.out.println("[extendedae_plus] 正在缩放样板:");
System.out.println(" 原始样板: " + base);
System.out.println(" 目标物品: " + target);
System.out.println(" 请求数量: " + requestedAmount);
System.out.println(" 缩放后输入: " + Arrays.toString(scaledInputs));
System.out.println(" 缩放后输出: " + Arrays.toString(scaledCondensedOutputs));
System.out.println(" 缩放后稀疏输入: " + Arrays.toString(scaledSparseInputs));
System.out.println(" 缩放后稀疏输出: " + Arrays.toString(scaledSparseOutputs));
LOGGER.info("[extendedae_plus] 正在缩放样板: 目标物品: {} 请求数量: {} 缩放后输入: {} 缩放后输出: {} 缩放后稀疏输入: {} 缩放后稀疏输出: {}",
target,
requestedAmount,
Arrays.toString(scaledInputs),
Arrays.toString(scaledCondensedOutputs),
Arrays.toString(scaledSparseInputs),
Arrays.toString(scaledSparseOutputs));
return new ScaledProcessingPattern(base,

View File

@ -0,0 +1,71 @@
package com.extendedae_plus.util;
import java.util.ArrayDeque;
import java.util.Deque;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
/**
* Thread-local stack holder for requested amounts to support nested requests.
*/
public final class RequestedAmountHolder {
private static final ThreadLocal<Deque<Long>> HOLDER = ThreadLocal.withInitial(ArrayDeque::new);
private RequestedAmountHolder() {
}
/**
* Push a requested amount onto the thread-local stack.
*/
public static void push(long v) {
Deque<Long> dq = HOLDER.get();
dq.push(v);
LOGGER.info("[extendedae_plus] 请求数量已推入堆栈: {} ; depth={}", v, dq.size());
}
/**
* Pop the top value from the thread-local stack. Safe if empty.
*/
public static void pop() {
Deque<Long> dq = HOLDER.get();
if (dq.isEmpty()) {
LOGGER.info("[extendedae_plus] 请求数量堆栈为空,无法弹出");
return;
}
Long popped = dq.pop();
LOGGER.info("[extendedae_plus] 请求数量已弹出堆栈: {} ; depth={}", popped, dq.size());
}
/**
* Peek the current requested amount or return 0 if none.
*/
public static long get() {
Deque<Long> dq = HOLDER.get();
Long v = dq.peek();
LOGGER.info("[extendedae_plus] 当前请求数量: {} ; depth={}", v, dq.size());
return v == null ? 0L : v;
}
/**
* Clear the entire stack for this thread.
*/
public static void clearAll() {
HOLDER.get().clear();
LOGGER.info("[extendedae_plus] 请求数量堆栈已清空");
}
/**
* 返回当前线程堆栈深度仅供日志/诊断使用
*/
public static int depth() {
return HOLDER.get().size();
}
/**
* 返回当前线程堆栈的字符串表示仅供日志/诊断使用
*/
public static String snapshot() {
return HOLDER.get().toString();
}
}

View File

@ -32,7 +32,6 @@
"ae2.MEStorageMenuMixin",
"ae2.PatternEncodingTermMenuMixin",
"ae2.PatternProviderLogicAdvancedMixin",
"ae2.PatternProviderLogicContainsRedirectMixin",
"ae2.PatternProviderMenuAdvancedMixin",
"ae2.accessor.MEStorageMenuAccessor",
"ae2.accessor.PatternEncodingTermMenuAccessor",
@ -43,7 +42,9 @@
"autopattern.CraftingCalculationAccessor",
"autopattern.CraftingServiceGetProvidersMixin",
"autopattern.CraftingTreeNodeAccessor",
"autopattern.CraftingTreeNodeMixin",
"autopattern.CraftingTreeProcessMixin",
"autopattern.PatternProviderLogicContainsRedirectMixin",
"extendedae.ContainerExPatternProviderMixin",
"extendedae.ContainerExPatternTerminalMixin",
"extendedae.ContainerWirelessExPatternTerminalMixin",