diff --git a/src/main/java/com/extendedae_plus/ae/api/crafting/ScaledProcessingPattern.java b/src/main/java/com/extendedae_plus/ae/api/crafting/ScaledProcessingPattern.java index c402127..e3952d6 100644 --- a/src/main/java/com/extendedae_plus/ae/api/crafting/ScaledProcessingPattern.java +++ b/src/main/java/com/extendedae_plus/ae/api/crafting/ScaledProcessingPattern.java @@ -27,6 +27,8 @@ public class ScaledProcessingPattern implements IPatternDetails { private transient volatile GenericStack[] outputsCache; private transient volatile GenericStack[] sparseInputsCache; private transient volatile GenericStack[] sparseOutputsCache; + // per-provider scaling limit (0 = no limit). Can be updated from UI via provider settings. + private int perProviderScalingLimit = 0; public ScaledProcessingPattern(AEProcessingPattern original, AEItemKey definition, long multiplier) { this.original = Objects.requireNonNull(original); @@ -34,6 +36,14 @@ public class ScaledProcessingPattern implements IPatternDetails { this.multiplier = multiplier <= 0 ? 1L : multiplier; } + public int getPerProviderScalingLimit() { + return this.perProviderScalingLimit; + } + + public void setPerProviderScalingLimit(int limit) { + this.perProviderScalingLimit = Math.max(0, limit); + } + /* -------------------- API 实现 -------------------- */ public AEProcessingPattern getOriginal() { diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingAwarePattern.java b/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingAwarePattern.java index c62dc81..b33da38 100644 --- a/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingAwarePattern.java +++ b/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingAwarePattern.java @@ -3,4 +3,7 @@ package com.extendedae_plus.api.smartDoubling; public interface ISmartDoublingAwarePattern { boolean eap$allowScaling(); void eap$setAllowScaling(boolean allow); + /** per-provider scaling limit: 0 means no limit */ + int eap$getScalingLimit(); + void eap$setScalingLimit(int limit); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java index a86029b..c14fca6 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java @@ -9,6 +9,8 @@ import org.spongepowered.asm.mixin.Unique; public class AEProcessingPatternMixin implements ISmartDoublingAwarePattern { @Unique private boolean eap$allowScaling = false; // 默认不允许缩放 + @Unique + private int eap$scalingLimit = 0; // 0 表示不限制 @Override public boolean eap$allowScaling() { @@ -19,4 +21,14 @@ public class AEProcessingPatternMixin implements ISmartDoublingAwarePattern { public void eap$setAllowScaling(boolean allow) { this.eap$allowScaling = allow; } + + @Override + public int eap$getScalingLimit() { + return this.eap$scalingLimit; + } + + @Override + public void eap$setScalingLimit(int limit) { + this.eap$scalingLimit = Math.max(0, limit); + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java index d78a7eb..8d0887b 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java @@ -22,6 +22,13 @@ public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder { @Unique private boolean eap$smartDoubling = false; + @Unique + private static final Object EAP_SCALING_LOCK = new Object(); + @Unique + private static final java.util.concurrent.ScheduledExecutorService EAP_EXECUTOR = + java.util.concurrent.Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "eap-scaling-save")); + @Unique + private java.util.concurrent.ScheduledFuture eap$pendingScalingSave = null; @Override public boolean eap$getSmartDoubling() { @@ -48,6 +55,29 @@ public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder { @Inject(method = "writeToNBT", at = @At("TAIL")) private void eap$writeSmartDoublingToNbt(CompoundTag tag, CallbackInfo ci) { tag.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + // persist any pattern-level scaling limits + try { + var list = ((PatternProviderLogicAccessor) this).eap$patterns(); + int[] limits = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + var details = list.get(i); + if (details instanceof com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern sp) { + limits[i] = sp.getPerProviderScalingLimit(); + } else if (details instanceof appeng.crafting.pattern.AEProcessingPattern base && base instanceof ISmartDoublingAwarePattern aware) { + limits[i] = aware.eap$getScalingLimit(); + } else { + limits[i] = 0; + } + } + var listTag = new net.minecraft.nbt.ListTag(); + for (int v : limits) { + var c = new CompoundTag(); + c.putInt("limit", v); + listTag.add(c); + } + tag.put("eap_scaling_limits", listTag); + } catch (Throwable ignored) { + } } @Inject(method = "readFromNBT", at = @At("TAIL")) @@ -55,6 +85,23 @@ public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder { if (tag.contains(EAP_SMART_DOUBLING_KEY)) { this.eap$smartDoubling = tag.getBoolean(EAP_SMART_DOUBLING_KEY); } + try { + if (tag.contains("eap_scaling_limits")) { + var list = ((PatternProviderLogicAccessor) this).eap$patterns(); + var limitsTag = tag.getList("eap_scaling_limits", net.minecraft.nbt.Tag.TAG_COMPOUND); + int n = Math.min(list.size(), limitsTag.size()); + for (int i = 0; i < n; i++) { + var c = limitsTag.getCompound(i); + int lim = c.getInt("limit"); + var details = list.get(i); + if (details instanceof com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern sp) { + sp.setPerProviderScalingLimit(lim); + } else if (details instanceof appeng.crafting.pattern.AEProcessingPattern base && base instanceof ISmartDoublingAwarePattern aware) { + aware.eap$setScalingLimit(lim); + } + } + } + } catch (Throwable ignored) {} } @Inject(method = "updatePatterns", at = @At("TAIL")) @@ -71,6 +118,32 @@ public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder { } } + // called by UI when user changes per-provider limit; apply with debounce and save + @Unique + public void eap$onPerProviderLimitChanged(int patternIndex, int newLimit) { + try { + var list = ((PatternProviderLogicAccessor) this).eap$patterns(); + if (patternIndex < 0 || patternIndex >= list.size()) return; + var details = list.get(patternIndex); + if (details instanceof com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern sp) { + sp.setPerProviderScalingLimit(newLimit); + } else if (details instanceof appeng.crafting.pattern.AEProcessingPattern base && base instanceof ISmartDoublingAwarePattern aware) { + aware.eap$setScalingLimit(newLimit); + } + + synchronized (EAP_SCALING_LOCK) { + if (eap$pendingScalingSave != null) { + eap$pendingScalingSave.cancel(false); + } + eap$pendingScalingSave = EAP_EXECUTOR.schedule(() -> { + try { + this.saveChanges(); + } catch (Throwable ignored) {} + }, 1000, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } catch (Throwable ignored) {} + } + @Shadow public void saveChanges() {} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java index d8b4aee..08d6c69 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java @@ -28,6 +28,14 @@ public abstract class PatternProviderMenuDoublingMixin implements IPatternProvid @Unique @GuiSync(21) public boolean eap$SmartDoubling = false; + @Unique + @GuiSync(22) + public int eap$PerProviderScalingLimit = 0; // 0 = no limit + + public void eap$setPerProviderScalingLimit(int v) { + this.eap$PerProviderScalingLimit = Math.max(0, v); + // send to server via an existing packet channel or custom packet (not implemented here) + } @Inject(method = "broadcastChanges", at = @At("HEAD")) private void eap$syncSmartDoubling(CallbackInfo ci) { diff --git a/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java b/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java index eef400e..b93413d 100644 --- a/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java +++ b/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java @@ -56,6 +56,24 @@ public final class PatternScaler { long needed = requestedAmount / perOperationTarget + ((requestedAmount % perOperationTarget) == 0 ? 0 : 1); multiplier = needed <= 1L ? 1L : needed; } + + // 优先应用模式级别的限制(若 base 支持),然后是全局配置 + try { + int patternLimit = 0; + if (base instanceof ISmartDoublingAwarePattern aware) { + patternLimit = aware.eap$getScalingLimit(); + } + if (patternLimit > 0 && multiplier > patternLimit) { + multiplier = patternLimit; + } else { + int maxMul = ModConfig.INSTANCE.smartScalingMaxMultiplier; + if (maxMul > 0 && multiplier > maxMul) { + multiplier = maxMul; + } + } + } catch (Throwable ignore) { + // ignore config read errors + } // 小请求绕过:若请求量小且不会带来收益,则不启用缩放(返回 null) try { int minBenefit = ModConfig.INSTANCE.smartScalingMinBenefitFactor;