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 f86509e..5cb96bc 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 @@ -122,17 +122,17 @@ public class ScaledProcessingPattern implements IPatternDetails { return sb.toString(); } - private record ScaledInput(IInput delegate, long mul) implements IInput { + private record ScaledInput(IInput original, long multiplier) implements IInput { @Override - public GenericStack[] getPossibleInputs() {return delegate.getPossibleInputs();} + public GenericStack[] getPossibleInputs() {return original.getPossibleInputs();} @Override - public long getMultiplier() {return delegate.getMultiplier() * mul;} + public long getMultiplier() {return original.getMultiplier() * multiplier;} @Override - public boolean isValid(AEKey input, Level level) {return delegate.isValid(input, level);} + public boolean isValid(AEKey input, Level level) {return original.isValid(input, level);} @Override - public @Nullable AEKey getRemainingKey(AEKey template) {return delegate.getRemainingKey(template);} + public @Nullable AEKey getRemainingKey(AEKey template) {return original.getRemainingKey(template);} } } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingSimulationStateExt.java b/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingSimulationStateExt.java new file mode 100644 index 0000000..0758f54 --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingSimulationStateExt.java @@ -0,0 +1,8 @@ +package com.extendedae_plus.api.smartDoubling; + +import appeng.crafting.CraftingTreeProcess; + +public interface ICraftingSimulationStateExt { + void setSourceProcess(CraftingTreeProcess process); + CraftingTreeProcess getSourceProcess(); +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingTreeProcessExt.java b/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingTreeProcessExt.java new file mode 100644 index 0000000..ee6d315 --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/smartDoubling/ICraftingTreeProcessExt.java @@ -0,0 +1,7 @@ +package com.extendedae_plus.api.smartDoubling; + +import appeng.api.networking.crafting.ICraftingService; + +public interface ICraftingTreeProcessExt { + ICraftingService getCraftingService(); +} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingProviderListAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingProviderListAccessor.java deleted file mode 100644 index 21239d0..0000000 --- a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingProviderListAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.extendedae_plus.mixin.ae2.autopattern; - -import appeng.api.networking.crafting.ICraftingProvider; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import java.util.List; - -@Mixin(targets = "appeng.me.service.helpers.NetworkCraftingProviders$CraftingProviderList") -public interface CraftingProviderListAccessor { - @Accessor(value = "providers",remap = false) - List getProviders(); -} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateAccessor.java new file mode 100644 index 0000000..7aef8d5 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateAccessor.java @@ -0,0 +1,14 @@ +package com.extendedae_plus.mixin.ae2.autopattern; + +import appeng.api.crafting.IPatternDetails; +import appeng.crafting.inv.CraftingSimulationState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(value = CraftingSimulationState.class,remap = false) +public interface CraftingSimulationStateAccessor { + @Accessor("crafts") + Map getCrafts(); +} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateMixin.java index db5681c..5ab0f60 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingSimulationStateMixin.java @@ -1,101 +1,116 @@ package com.extendedae_plus.mixin.ae2.autopattern; import appeng.api.crafting.IPatternDetails; +import appeng.crafting.CraftingCalculation; +import appeng.crafting.CraftingPlan; +import appeng.crafting.CraftingTreeProcess; import appeng.crafting.inv.CraftingSimulationState; import appeng.crafting.pattern.AEProcessingPattern; +import appeng.me.service.CraftingService; import com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern; +import com.extendedae_plus.api.smartDoubling.ICraftingSimulationStateExt; +import com.extendedae_plus.api.smartDoubling.ICraftingTreeProcessExt; import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern; import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.util.smartDoubling.PatternScaler; -import org.spongepowered.asm.mixin.Final; +import com.google.common.collect.Iterables; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +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.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.Map; -@SuppressWarnings({"AddedMixinMembersNamePattern", "MissingUnique"}) +@SuppressWarnings({"AddedMixinMembersNamePattern"}) @Mixin(value = CraftingSimulationState.class, remap = false) -public abstract class CraftingSimulationStateMixin { +public abstract class CraftingSimulationStateMixin implements ICraftingSimulationStateExt { + @Unique private CraftingTreeProcess sourceProcess; - @Shadow @Final private Map crafts; + /** + * 替换 CraftingPlan 构建逻辑,在此统一处理样板倍率 + */ + @Inject(method = "buildCraftingPlan", at = @At("HEAD")) + private static void onBuildCraftingPlan(CraftingSimulationState state, CraftingCalculation calculation, long calculatedAmount, CallbackInfoReturnable cir) { + CraftingSimulationStateAccessor accessor = (CraftingSimulationStateAccessor) state; + Map crafts = accessor.getCrafts(); + // 新建 Map 存放最终分配后的 crafts + Map finalCrafts = new LinkedHashMap<>(); - /** 仅用于无限制缩放时的合并缓存 */ - private final Map scaledCache = new IdentityHashMap<>(); + for (Map.Entry entry : crafts.entrySet()) { + IPatternDetails details = entry.getKey(); + long totalAmount = entry.getValue(); - @Inject(method = "addCrafting", at = @At("HEAD"), cancellable = true) - private void onAddCrafting(IPatternDetails details, long craftsAmount, CallbackInfo ci) { - ci.cancel(); - if (craftsAmount <= 0 || details == null) return; + // 非 AEProcessingPattern 直接保留 + if (!(details instanceof AEProcessingPattern processingPattern)) { + finalCrafts.put(details, totalAmount); + continue; + } - // 仅处理 AEProcessingPattern - if (!(details instanceof AEProcessingPattern processingPattern)) { - crafts.merge(details, craftsAmount, Long::sum); - return; + boolean allowScaling = false; + int perCraftLimit = 0; + if (processingPattern instanceof ISmartDoublingAwarePattern aware) { + allowScaling = aware.eap$allowScaling(); + perCraftLimit = aware.eap$getMultiplierLimit(); + } + + if (!allowScaling || totalAmount <= 1) { + finalCrafts.put(processingPattern, totalAmount); + continue; + } + + if (perCraftLimit <= 0 && ModConfig.INSTANCE.smartScalingMaxMultiplier > 0) { + perCraftLimit = ModConfig.INSTANCE.smartScalingMaxMultiplier; + } + + // 获取供应器数量 + CraftingTreeProcess process = ((ICraftingSimulationStateExt) state).getSourceProcess(); + CraftingService craftingService = (CraftingService) ((ICraftingTreeProcessExt) process).getCraftingService(); + long providerCount = Iterables.size(craftingService.getProviders(processingPattern)); + if (providerCount <= 0) providerCount = 1; + + if (perCraftLimit <= 0) { + // 无限倍率 → 按供应器均分并处理余数 + long base = totalAmount / providerCount; + long remainder = totalAmount % providerCount; + + if (remainder > 0) { + ScaledProcessingPattern scaled_r = PatternScaler.createScaled(processingPattern, base + remainder); + finalCrafts.put(scaled_r, 1L); + ScaledProcessingPattern scaled_b = PatternScaler.createScaled(processingPattern, base); + finalCrafts.put(scaled_b, providerCount - 1); + } else { + ScaledProcessingPattern scaled = PatternScaler.createScaled(processingPattern, base); + finalCrafts.put(scaled, providerCount); + } + } else { + // 有限制 → 拆分 full + remainder + long fullCrafts = totalAmount / perCraftLimit; + long remainder = totalAmount % perCraftLimit; + + if (fullCrafts > 0) { + ScaledProcessingPattern scaledFull = PatternScaler.createScaled(processingPattern, perCraftLimit); + finalCrafts.put(scaledFull, fullCrafts); + } + if (remainder > 0) { + ScaledProcessingPattern scaledRem = PatternScaler.createScaled(processingPattern, remainder); + finalCrafts.put(scaledRem, 1L); + } + } } - boolean allowScaling = false; - int perCraftLimit = 0; - - if (processingPattern instanceof ISmartDoublingAwarePattern aware) { - allowScaling = aware.eap$allowScaling(); - perCraftLimit = aware.eap$getMultiplierLimit(); // 样板供应器限制 - } - - // 样板不允许缩放 或者 需求量为 1 → 直接合并 - if (!allowScaling || craftsAmount == 1) { - crafts.merge(processingPattern, craftsAmount, Long::sum); - return; - } - - // 样板无限制时应用全局配置 - if (perCraftLimit <= 0 && ModConfig.INSTANCE.smartScalingMaxMultiplier > 0) { - perCraftLimit = ModConfig.INSTANCE.smartScalingMaxMultiplier; - } - - // 根据限制处理 - if (perCraftLimit <= 0) { - // 无限制 → 合并倍率并复用对象 - mergeUnlimited(processingPattern, craftsAmount); - } else { - // 有限制 → 拆分 full + remainder - splitLimited(processingPattern, craftsAmount, perCraftLimit); - } + crafts.clear(); + crafts.putAll(finalCrafts); } - /** 无限制:合并倍率并复用 ScaledProcessingPattern 或 AAE 扩展 */ - private void mergeUnlimited(AEProcessingPattern original, long multiplier) { - ScaledProcessingPattern existing = scaledCache.get(original); - long total = multiplier; - - if (existing != null) { - total += existing.getMultiplier(); - crafts.remove(existing); - } - - // 使用 PatternScaler 自动选择原版或 AAE 扩展 - ScaledProcessingPattern scaled = PatternScaler.createScaled(original, total); - - scaledCache.put(original, scaled); - crafts.put(scaled, 1L); + @Override + public CraftingTreeProcess getSourceProcess() { + return this.sourceProcess; } - /** 有限制:拆分 full + remainder,并支持原版/AAE 扩展 */ - private void splitLimited(AEProcessingPattern original, long totalAmount, int limit) { - long fullCrafts = totalAmount / limit; - long remainder = totalAmount % limit; - - if (fullCrafts > 0) { - ScaledProcessingPattern scaledFull = PatternScaler.createScaled(original, limit); - crafts.merge(scaledFull, fullCrafts, Long::sum); - } - - if (remainder > 0) { - ScaledProcessingPattern scaledRemainder = PatternScaler.createScaled(original, remainder); - crafts.merge(scaledRemainder, 1L, Long::sum); - } + @Override + public void setSourceProcess(CraftingTreeProcess process) { + this.sourceProcess = process; } -} \ No newline at end of file +} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java new file mode 100644 index 0000000..fe28216 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java @@ -0,0 +1,39 @@ +package com.extendedae_plus.mixin.ae2.autopattern; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.networking.crafting.ICraftingService; +import appeng.crafting.CraftingCalculation; +import appeng.crafting.CraftingTreeNode; +import appeng.crafting.CraftingTreeProcess; +import appeng.crafting.inv.CraftingSimulationState; +import com.extendedae_plus.api.smartDoubling.ICraftingSimulationStateExt; +import com.extendedae_plus.api.smartDoubling.ICraftingTreeProcessExt; +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.CallbackInfo; + +@SuppressWarnings({"AddedMixinMembersNamePattern"}) +@Mixin(value = CraftingTreeProcess.class, remap = false) +public class CraftingTreeProcessMixin implements ICraftingTreeProcessExt { + @Unique private ICraftingService craftingService; + + @Inject(method = "",at = @At("RETURN")) + private void init(ICraftingService cc, CraftingCalculation job, IPatternDetails details, CraftingTreeNode craftingTreeNode, CallbackInfo ci) { + this.craftingService = cc; + } + + @Inject( + method = "request", + at = @At("HEAD") + ) + private void bindSimulationState(CraftingSimulationState inv, long times, CallbackInfo ci) { + ((ICraftingSimulationStateExt) inv).setSourceProcess((CraftingTreeProcess) (Object) this); + } + + @Override + public ICraftingService getCraftingService() { + return this.craftingService; + } +} diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index 90943de..24eb674 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -51,9 +51,10 @@ "ae2.accessor.PatternEncodingTermMenuAccessor", "ae2.accessor.PatternProviderLogicAccessor", "ae2.accessor.PatternProviderMenuAccessor", - "ae2.autopattern.CraftingProviderListAccessor", "ae2.autopattern.CraftingServiceGetProvidersMixin", + "ae2.autopattern.CraftingSimulationStateAccessor", "ae2.autopattern.CraftingSimulationStateMixin", + "ae2.autopattern.CraftingTreeProcessMixin", "ae2.autopattern.PatternProviderLogicContainsRedirectMixin", "ae2.compat.PatternProviderCompatMixin", "ae2.compat.PatternProviderLogicCompatMixin",