feat: 添加样板供应器级别智能翻倍限制

fix: 修复aae高级样板不生效智能翻倍的问题
This commit is contained in:
C-H716 2026-06-02 19:37:48 +08:00
parent 6a0c37af4f
commit 60be80c397
22 changed files with 554 additions and 46 deletions

View File

@ -0,0 +1,14 @@
package com.extendedae_plus.api;
import net.minecraft.client.gui.GuiGraphics;
/**
* 用于在 AEBaseScreen.drawBG 中渲染输入框背景的回调接口
*/
public interface IInputBackgroundRenderer {
/**
* 在背景层绘制输入框外部背景
* @param guiGraphics 图形上下文
*/
void eap$renderInputBackground(GuiGraphics guiGraphics);
}

View File

@ -4,4 +4,6 @@ import appeng.api.config.YesNo;
public interface IPatternProviderMenuDoublingSync {
YesNo eap$getSmartDoublingSynced();
int eap$getScalingLimit();
}

View File

@ -1,6 +0,0 @@
package com.extendedae_plus.api.smartDoubling;
public interface ISmartDoubling {
boolean eap$getSmartDoubling();
void eap$setSmartDoubling(boolean value);
}

View File

@ -0,0 +1,7 @@
package com.extendedae_plus.api.smartDoubling;
public interface ISmartDoublingHolder {
int eap$getProviderSmartDoublingLimit();
void eap$setProviderSmartDoublingLimit(int limit);
}

View File

@ -1,7 +1,23 @@
package com.extendedae_plus.init;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.network.*;
import com.extendedae_plus.network.CancelPendingPatternC2SPacket;
import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket;
import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket;
import com.extendedae_plus.network.CreateAndUploadPatternC2SPacket;
import com.extendedae_plus.network.CreateCtrlQPatternC2SPacket;
import com.extendedae_plus.network.GlobalToggleProviderModesC2SPacket;
import com.extendedae_plus.network.InterfaceAdjustConfigAmountC2SPacket;
import com.extendedae_plus.network.OpenProviderUiC2SPacket;
import com.extendedae_plus.network.ProvidersListS2CPacket;
import com.extendedae_plus.network.RequestProvidersListC2SPacket;
import com.extendedae_plus.network.ScaleEncodingPatternC2SPacket;
import com.extendedae_plus.network.ScalePatternsC2SPacket;
import com.extendedae_plus.network.SetPatternHighlightS2CPacket;
import com.extendedae_plus.network.SetPerProviderScalingLimitC2SPacket;
import com.extendedae_plus.network.SetProviderPageS2CPacket;
import com.extendedae_plus.network.UploadEncodedPatternToProviderC2SPacket;
import com.extendedae_plus.network.UploadInventoryPatternToProviderC2SPacket;
import com.extendedae_plus.network.crafting.ForceCraftStartFlagC2SPacket;
import com.extendedae_plus.network.crafting.ManualCraftingStatusS2CPacket;
import com.extendedae_plus.network.packet.EAPConfigButtonPacket;
@ -67,5 +83,6 @@ public class ModNetwork {
ManualCraftingStatusS2CPacket::handle);
registrar.playToServer(EAPConfigButtonPacket.TYPE, EAPConfigButtonPacket.STREAM_CODEC, EAPConfigButtonPacket::handleOnServer);
registrar.playToServer(SetPerProviderScalingLimitC2SPacket.TYPE, SetPerProviderScalingLimitC2SPacket.STREAM_CODEC, SetPerProviderScalingLimitC2SPacket::handle);
}
}

View File

@ -2,13 +2,21 @@ package com.extendedae_plus.mixin.advancedae.client.gui;
import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.Icon;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.AETextField;
import com.extendedae_plus.api.IInputBackgroundRenderer;
import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.client.gui.widgets.EAPServerSettingToggleButton;
import com.extendedae_plus.network.SetPerProviderScalingLimitC2SPacket;
import com.extendedae_plus.util.GuiUtil;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.neoforged.neoforge.network.PacketDistributor;
import net.pedroksl.advanced_ae.client.gui.AdvPatternProviderScreen;
import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu;
import org.spongepowered.asm.mixin.Mixin;
@ -17,15 +25,23 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections;
/**
* 为高级ae样板供应器界面添加高级阻挡模式按钮
* 为高级ae样板供应器界面添加"高级阻挡模式"按钮
* - 位于左侧工具栏
* - 点击仅发送 C2S 切换请求状态由 AE2 @GuiSync 回传决定
*/
@Mixin(AdvPatternProviderScreen.class)
public abstract class AdvPatternProviderSmartFeaturesMixin extends AEBaseScreen<AdvPatternProviderMenu> {
public abstract class AdvPatternProviderSmartFeaturesMixin extends AEBaseScreen<AdvPatternProviderMenu> implements IInputBackgroundRenderer {
@Unique private EAPServerSettingToggleButton<YesNo> eap$AdvancedBlockingToggle;
@Unique private EAPServerSettingToggleButton<YesNo> eap$SmartDoublingToggle;
@Unique private AETextField eap$PerProviderLimitInput;
@Unique private int eap$PerProviderScalingLimit = 0;
@Unique private int eap$inputBgX;
@Unique private int eap$inputBgY;
@Unique private int eap$inputBgW;
@Unique private int eap$inputBgH;
public AdvPatternProviderSmartFeaturesMixin(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
@ -37,6 +53,70 @@ public abstract class AdvPatternProviderSmartFeaturesMixin extends AEBaseScreen<
this.addToLeftToolbar(this.eap$AdvancedBlockingToggle);
this.eap$SmartDoublingToggle = new EAPServerSettingToggleButton<>(EAPSettings.SMART_DOUBLING, YesNo.YES);
this.addToLeftToolbar(this.eap$SmartDoublingToggle);
if (menu instanceof IPatternProviderMenuDoublingSync sync) {
this.eap$PerProviderScalingLimit = sync.eap$getScalingLimit();
}
this.eap$PerProviderLimitInput = GuiUtil.createPerProviderLimitInput(this.style, this.font, this.eap$PerProviderScalingLimit, limit -> {
this.eap$PerProviderScalingLimit = limit;
PacketDistributor.sendToServer(new SetPerProviderScalingLimitC2SPacket(limit));
});
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
/**
* 刷新输入框的内容和可见性
*/
@Unique
private void eap$updateLimitInput() {
if (this.eap$PerProviderLimitInput == null) return;
int remoteLimit = this.eap$PerProviderScalingLimit;
// 获取服务端最新的 scaling limit
if (this.menu instanceof IPatternProviderMenuDoublingSync sync) {
remoteLimit = sync.eap$getScalingLimit();
}
boolean focused = this.eap$PerProviderLimitInput.isFocused();
// 如果未聚焦且服务端有变化则同步显示
if (!focused && remoteLimit != this.eap$PerProviderScalingLimit) {
this.eap$PerProviderScalingLimit = remoteLimit;
this.eap$PerProviderLimitInput.setValue(String.valueOf(remoteLimit));
}
if (this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES) {
// 智能翻倍启用时确保输入框可见
if (!this.renderables.contains(this.eap$PerProviderLimitInput)) {
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
// 未聚焦且内容为空时显示0
if (!focused && this.eap$PerProviderLimitInput.getValue().trim().isEmpty()) {
this.eap$PerProviderLimitInput.setValue("0");
}
Button ref = eap$SmartDoublingToggle;
if (ref != null) {
int visualWidth = this.eap$PerProviderLimitInput.getWidth() + 4 + this.font.width("_");
int visualHeight = 16;
int padding = 2;
int ex = ref.getX() - visualWidth - 5 - padding ;
int ey = ref.getY() + (ref.getHeight() - visualHeight) / 2 - padding + 6;
this.eap$PerProviderLimitInput.setX(ex + padding);
this.eap$PerProviderLimitInput.setY(ey + padding);
this.eap$inputBgX = ex;
this.eap$inputBgY = ey;
this.eap$inputBgW = visualWidth + padding * 2;
this.eap$inputBgH = visualHeight + padding * 2;
}
String cur = this.eap$PerProviderLimitInput.getValue();
if (cur.isBlank()) cur = "0";
this.eap$PerProviderLimitInput.setTooltipMessage(Collections.singletonList(Component.translatable("gui.extendedae_plus.per_provider_limit.tooltip", cur)));
} else {
// 智能翻倍未启用时移除输入框
this.removeWidget(this.eap$PerProviderLimitInput);
}
}
// 每帧刷新仅从菜单(@GuiSync)同步布尔值保持按钮状态一致
@ -48,5 +128,17 @@ public abstract class AdvPatternProviderSmartFeaturesMixin extends AEBaseScreen<
if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingToggle.set(sync.eap$getAdvancedBlockingSynced());
}
eap$updateLimitInput();
}
@Override
public void eap$renderInputBackground(GuiGraphics guiGraphics) {
if (this.eap$SmartDoublingToggle != null && this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES
&& this.eap$PerProviderLimitInput != null && this.eap$PerProviderLimitInput.isVisible()) {
Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter()
.dest(this.eap$inputBgX - 5, this.eap$inputBgY-3, this.eap$inputBgW + 6, this.eap$inputBgH- 2)
.blit(guiGraphics);
}
}
}

View File

@ -2,13 +2,21 @@ package com.extendedae_plus.mixin.advancedae.client.gui;
import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.Icon;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.AETextField;
import com.extendedae_plus.api.IInputBackgroundRenderer;
import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.client.gui.widgets.EAPServerSettingToggleButton;
import com.extendedae_plus.network.SetPerProviderScalingLimitC2SPacket;
import com.extendedae_plus.util.GuiUtil;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.neoforged.neoforge.network.PacketDistributor;
import net.pedroksl.advanced_ae.client.gui.SmallAdvPatternProviderScreen;
import net.pedroksl.advanced_ae.gui.advpatternprovider.SmallAdvPatternProviderMenu;
import org.spongepowered.asm.mixin.Mixin;
@ -17,15 +25,23 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections;
/**
* 为高级ae样板供应器界面添加高级阻挡模式按钮
* 为高级ae样板供应器界面添加"高级阻挡模式"按钮
* - 位于左侧工具栏
* - 点击仅发送 C2S 切换请求状态由 AE2 @GuiSync 回传决定
*/
@Mixin(SmallAdvPatternProviderScreen.class)
public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<SmallAdvPatternProviderMenu> {
public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<SmallAdvPatternProviderMenu> implements IInputBackgroundRenderer {
@Unique private EAPServerSettingToggleButton<YesNo> eap$AdvancedBlockingToggle;
@Unique private EAPServerSettingToggleButton<YesNo> eap$SmartDoublingToggle;
@Unique private AETextField eap$PerProviderLimitInput;
@Unique private int eap$PerProviderScalingLimit = 0;
@Unique private int eap$inputBgX;
@Unique private int eap$inputBgY;
@Unique private int eap$inputBgW;
@Unique private int eap$inputBgH;
public SmallAdvPatternProviderScreenMixin(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
@ -37,6 +53,70 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
this.addToLeftToolbar(this.eap$AdvancedBlockingToggle);
this.eap$SmartDoublingToggle = new EAPServerSettingToggleButton<>(EAPSettings.SMART_DOUBLING, YesNo.YES);
this.addToLeftToolbar(this.eap$SmartDoublingToggle);
if (menu instanceof IPatternProviderMenuDoublingSync sync) {
this.eap$PerProviderScalingLimit = sync.eap$getScalingLimit();
}
this.eap$PerProviderLimitInput = GuiUtil.createPerProviderLimitInput(this.style, this.font, this.eap$PerProviderScalingLimit, limit -> {
this.eap$PerProviderScalingLimit = limit;
PacketDistributor.sendToServer(new SetPerProviderScalingLimitC2SPacket(limit));
});
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
/**
* 刷新输入框的内容和可见性
*/
@Unique
private void eap$updateLimitInput() {
if (this.eap$PerProviderLimitInput == null) return;
int remoteLimit = this.eap$PerProviderScalingLimit;
// 获取服务端最新的 scaling limit
if (this.menu instanceof IPatternProviderMenuDoublingSync sync) {
remoteLimit = sync.eap$getScalingLimit();
}
boolean focused = this.eap$PerProviderLimitInput.isFocused();
// 如果未聚焦且服务端有变化则同步显示
if (!focused && remoteLimit != this.eap$PerProviderScalingLimit) {
this.eap$PerProviderScalingLimit = remoteLimit;
this.eap$PerProviderLimitInput.setValue(String.valueOf(remoteLimit));
}
if (this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES) {
// 智能翻倍启用时确保输入框可见
if (!this.renderables.contains(this.eap$PerProviderLimitInput)) {
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
// 未聚焦且内容为空时显示0
if (!focused && this.eap$PerProviderLimitInput.getValue().trim().isEmpty()) {
this.eap$PerProviderLimitInput.setValue("0");
}
Button ref = eap$SmartDoublingToggle;
if (ref != null) {
int visualWidth = this.eap$PerProviderLimitInput.getWidth() + 4 + this.font.width("_");
int visualHeight = 16;
int padding = 2;
int ex = ref.getX() - visualWidth - 5 - padding ;
int ey = ref.getY() + (ref.getHeight() - visualHeight) / 2 - padding + 6;
this.eap$PerProviderLimitInput.setX(ex + padding);
this.eap$PerProviderLimitInput.setY(ey + padding);
this.eap$inputBgX = ex;
this.eap$inputBgY = ey;
this.eap$inputBgW = visualWidth + padding * 2;
this.eap$inputBgH = visualHeight + padding * 2;
}
String cur = this.eap$PerProviderLimitInput.getValue();
if (cur.isBlank()) cur = "0";
this.eap$PerProviderLimitInput.setTooltipMessage(Collections.singletonList(Component.translatable("gui.extendedae_plus.per_provider_limit.tooltip", cur)));
} else {
// 智能翻倍未启用时移除输入框
this.removeWidget(this.eap$PerProviderLimitInput);
}
}
// 每帧刷新仅从菜单(@GuiSync)同步布尔值保持按钮状态一致
@ -48,5 +128,17 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingToggle.set(sync.eap$getAdvancedBlockingSynced());
}
eap$updateLimitInput();
}
@Override
public void eap$renderInputBackground(GuiGraphics guiGraphics) {
if (this.eap$SmartDoublingToggle != null && this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES
&& this.eap$PerProviderLimitInput != null && this.eap$PerProviderLimitInput.isVisible()) {
Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter()
.dest(this.eap$inputBgX - 5, this.eap$inputBgY-3, this.eap$inputBgW + 6, this.eap$inputBgH- 2)
.blit(guiGraphics);
}
}
}

View File

@ -8,6 +8,8 @@ import appeng.api.util.IConfigManager;
import appeng.util.ConfigManager;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.util.smartDoubling.PatternScaler;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
@ -15,6 +17,7 @@ import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogicHost;
import org.spongepowered.asm.mixin.Final;
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;
@ -22,9 +25,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(value = AdvPatternProviderLogic.class, remap = false)
public class AdvPatternProviderLogicDoublingMixin {
public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolder {
@Unique private static final String EAP_PROVIDER_SCALING_LIMIT = "eap_provider_scaling_limit";
@Shadow @Final private List<IPatternDetails> patterns;
@Shadow @Final private IConfigManager configManager;
@Unique private int eap$providerScalingLimit = 0; // 供应器级别的上限0 表示不限制
@Shadow
public IConfigManager getConfigManager() {return null;}
@ -32,6 +37,17 @@ public class AdvPatternProviderLogicDoublingMixin {
@Shadow
public void updatePatterns() {}
@Override
public int eap$getProviderSmartDoublingLimit() {
return this.eap$providerScalingLimit;
}
@Override
public void eap$setProviderSmartDoublingLimit(int limit) {
this.eap$providerScalingLimit = limit;
this.updatePatterns();
}
@Inject(
method = "<init>(Lappeng/api/networking/IManagedGridNode;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;I)V",
at = @At("TAIL")
@ -49,24 +65,37 @@ public class AdvPatternProviderLogicDoublingMixin {
}
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$writeSmartDoublingToNbt(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
// 保存供应器级别上限
tag.putInt(EAP_PROVIDER_SCALING_LIMIT, this.eap$providerScalingLimit);
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$readSmartDoublingFromNbt(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
// TODO
// 适配旧版本中的数据后续版本删除
if (tag.contains("eap_smart_doubling")) {
this.configManager.putSetting(EAPSettings.SMART_DOUBLING,
tag.getBoolean("eap_smart_doubling") ? YesNo.YES : YesNo.NO);
tag.getBoolean("eap_smart_doubling") ? YesNo.YES : YesNo.NO
);
tag.remove("eap_smart_doubling");
}
if (tag.contains(EAP_PROVIDER_SCALING_LIMIT)) {
this.eap$providerScalingLimit = tag.getInt(EAP_PROVIDER_SCALING_LIMIT);
}
}
@Inject(method = "updatePatterns", at = @At("TAIL"))
private void eap$applySmartDoublingToPatterns(CallbackInfo ci) {
IConfigManager configManager = this.getConfigManager();
boolean allowScaling = configManager.getSetting(EAPSettings.SMART_DOUBLING) == YesNo.YES;
int limit = this.eap$providerScalingLimit;
for (IPatternDetails details : this.patterns) {
if (details instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allowScaling);
aware.eap$setMultiplierLimit(PatternScaler.getComputedMul(details, limit));
}
}
}

View File

@ -4,6 +4,7 @@ import appeng.api.config.YesNo;
import appeng.menu.guisync.GuiSync;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu;
import org.spongepowered.asm.mixin.Final;
@ -18,11 +19,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Shadow @Final protected AdvPatternProviderLogic logic;
@Unique @GuiSync(21) private YesNo eap$SmartDoubling;
@Unique @GuiSync(22) private int eap$PerProviderScalingLimit = 0;
@Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((AdvPatternProviderMenu) (Object) this).isClientSide()) {
this.eap$SmartDoubling = this.logic.getConfigManager().getSetting(EAPSettings.SMART_DOUBLING);
var l = this.logic;
this.eap$SmartDoubling = l.getConfigManager().getSetting(EAPSettings.SMART_DOUBLING);
if (l instanceof ISmartDoublingHolder holder) {
this.eap$PerProviderScalingLimit = holder.eap$getProviderSmartDoublingLimit();
}
}
}
@ -30,4 +36,9 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro
public YesNo eap$getSmartDoublingSynced() {
return this.eap$SmartDoubling;
}
@Override
public int eap$getScalingLimit() {
return this.eap$PerProviderScalingLimit;
}
}

View File

@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(PatternProviderMenu.class)
public interface PatternProviderMenuAdvancedAccessor {
public interface PatternProviderMenuAccessor {
@Accessor("logic")
PatternProviderLogic eap$logic();
}

View File

@ -1,11 +1,11 @@
package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.crafting.CraftingCalculation;
import appeng.crafting.CraftingPlan;
import appeng.crafting.inv.CraftingSimulationState;
import appeng.me.service.CraftingService;
import appeng.api.networking.crafting.ICraftingProvider;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ICraftingCalculationExt;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
@ -37,21 +37,20 @@ public abstract class CraftingSimulationStateMixin {
Map<IPatternDetails, Integer> providerCountCache = new HashMap<>();
for (Map.Entry<IPatternDetails, Long> entry : crafts.entrySet()) {
IPatternDetails processingPattern = entry.getKey();
IPatternDetails details = entry.getKey();
long totalAmount = entry.getValue();
// AEProcessingPattern 直接保留
if (!(processingPattern instanceof ISmartDoublingAwarePattern aware)) {
finalCrafts.put(processingPattern, totalAmount);
// AEProcessingPattern/AdvProcessingPattern 直接保留
if (!(details instanceof ISmartDoublingAwarePattern aware)) {
finalCrafts.put(details, totalAmount);
continue;
}
boolean allowScaling = aware.eap$allowScaling();
int perCraftLimit = aware.eap$getMultiplierLimit();
if (!allowScaling || totalAmount <= 1) {
finalCrafts.put(processingPattern, totalAmount);
finalCrafts.put(details, totalAmount);
continue;
}
@ -62,12 +61,15 @@ public abstract class CraftingSimulationStateMixin {
if (perCraftLimit <= 0) {
// 检查是否开启 provider 轮询分配功能
if (ModConfigs.PROVIDER_ROUND_ROBIN_ENABLE.getRaw()) {
CraftingService craftingService = (CraftingService) ((ICraftingCalculationExt) calculation).getGrid().getCraftingService();
CraftingService craftingService = (CraftingService) ((ICraftingCalculationExt) calculation).getGrid()
.getCraftingService();
int providerCount = Math.max(
providerCountCache.computeIfAbsent(
getProviderCacheKey(processingPattern),
key -> countProvidersUpTo(craftingService.getProviders(key), totalAmount)),
1);
getProviderCacheKey(details),
key -> countProvidersUpTo(craftingService.getProviders(key), totalAmount)
),
1
);
// totalAmount < providerCount 只激活 totalAmount provider
if (totalAmount < providerCount) {
@ -79,19 +81,19 @@ public abstract class CraftingSimulationStateMixin {
// base+1 数量 remainder
if (remainder > 0) {
IPatternDetails scaledPlus = PatternScaler.createScaled(processingPattern, base + 1);
ScaledProcessingPattern scaledPlus = PatternScaler.createScaled(details, base + 1);
finalCrafts.merge(scaledPlus, remainder, Long::sum);
}
// base 数量 providerCount - remainder
long countBase = providerCount - remainder;
if (countBase > 0) {
IPatternDetails scaledBase = PatternScaler.createScaled(processingPattern, base);
ScaledProcessingPattern scaledBase = PatternScaler.createScaled(details, base);
finalCrafts.merge(scaledBase, countBase, Long::sum);
}
} else {
// 未开启轮询 直接分配一次总量
IPatternDetails scaled = PatternScaler.createScaled(processingPattern, totalAmount);
ScaledProcessingPattern scaled = PatternScaler.createScaled(details, totalAmount);
finalCrafts.put(scaled, 1L);
}
} else {
@ -100,11 +102,11 @@ public abstract class CraftingSimulationStateMixin {
long remainder = totalAmount % perCraftLimit;
if (fullCrafts > 0) {
IPatternDetails scaledFull = PatternScaler.createScaled(processingPattern, perCraftLimit);
ScaledProcessingPattern scaledFull = PatternScaler.createScaled(details, perCraftLimit);
finalCrafts.put(scaledFull, fullCrafts);
}
if (remainder > 0) {
IPatternDetails scaledRem = PatternScaler.createScaled(processingPattern, remainder);
ScaledProcessingPattern scaledRem = PatternScaler.createScaled(details, remainder);
finalCrafts.put(scaledRem, 1L);
}
}

View File

@ -14,6 +14,7 @@ import appeng.client.gui.style.Text;
import appeng.client.gui.style.TextAlignment;
import appeng.menu.slot.AppEngSlot;
import com.extendedae_plus.api.IExPatternPage;
import com.extendedae_plus.api.IInputBackgroundRenderer;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket;
import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket;
@ -318,4 +319,13 @@ public abstract class AEBaseScreenMixin {
}
} catch (Throwable ignored) {}
}
// drawBG 方法末尾调用输入框背景渲染
@Inject(method = "drawBG", at = @At("TAIL"), remap = false)
private void eap$renderInputBackground(GuiGraphics guiGraphics, int offsetX, int offsetY, int mouseX, int mouseY, float partialTicks, CallbackInfo ci) {
Object self = this;
if (self instanceof IInputBackgroundRenderer renderer) {
renderer.eap$renderInputBackground(guiGraphics);
}
}
}

View File

@ -2,32 +2,48 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.Icon;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.AETextField;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.IExPatternButton;
import com.extendedae_plus.api.IInputBackgroundRenderer;
import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.client.gui.widgets.EAPServerSettingToggleButton;
import com.extendedae_plus.network.SetPerProviderScalingLimitC2SPacket;
import com.extendedae_plus.util.GuiUtil;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.neoforged.neoforge.network.PacketDistributor;
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;
import java.util.Collections;
/**
* AE2 原版样板供应器界面添加高级阻挡模式按钮
* AE2 原版样板供应器界面添加"高级阻挡模式"按钮
* - 位于左侧工具栏
* - 点击仅发送 C2S 切换请求状态由 AE2 @GuiSync 回传决定
*/
@Mixin(value = PatternProviderScreen.class, remap = false)
public abstract class PatternProviderSmartFeaturesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
public abstract class PatternProviderSmartFeaturesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> implements IInputBackgroundRenderer {
@Unique private EAPServerSettingToggleButton<YesNo> eap$AdvancedBlockingToggle;
@Unique private EAPServerSettingToggleButton<YesNo> eap$SmartDoublingToggle;
@Unique private AETextField eap$PerProviderLimitInput;
@Unique private int eap$PerProviderScalingLimit = 0;
@Unique private int eap$inputBgX;
@Unique private int eap$inputBgY;
@Unique private int eap$inputBgW;
@Unique private int eap$inputBgH;
public PatternProviderSmartFeaturesMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
@ -39,8 +55,73 @@ public abstract class PatternProviderSmartFeaturesMixin<C extends PatternProvide
this.addToLeftToolbar(this.eap$AdvancedBlockingToggle);
this.eap$SmartDoublingToggle = new EAPServerSettingToggleButton<>(EAPSettings.SMART_DOUBLING, YesNo.YES);
this.addToLeftToolbar(this.eap$SmartDoublingToggle);
if (menu instanceof IPatternProviderMenuDoublingSync sync) {
this.eap$PerProviderScalingLimit = sync.eap$getScalingLimit();
}
this.eap$PerProviderLimitInput = GuiUtil.createPerProviderLimitInput(this.style, this.font, this.eap$PerProviderScalingLimit, limit -> {
this.eap$PerProviderScalingLimit = limit;
PacketDistributor.sendToServer(new SetPerProviderScalingLimitC2SPacket(limit));
});
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
/**
* 刷新输入框的内容和可见性
*/
@Unique
private void eap$updateLimitInput() {
if (this.eap$PerProviderLimitInput == null) return;
int remoteLimit = this.eap$PerProviderScalingLimit;
// 获取服务端最新的 scaling limit
if (this.menu instanceof IPatternProviderMenuDoublingSync sync) {
remoteLimit = sync.eap$getScalingLimit();
}
boolean focused = this.eap$PerProviderLimitInput.isFocused();
// 如果未聚焦且服务端有变化则同步显示
if (!focused && remoteLimit != this.eap$PerProviderScalingLimit) {
this.eap$PerProviderScalingLimit = remoteLimit;
this.eap$PerProviderLimitInput.setValue(String.valueOf(remoteLimit));
}
if (this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES) {
// 智能翻倍启用时确保输入框可见
if (!this.renderables.contains(this.eap$PerProviderLimitInput)) {
this.addRenderableWidget(this.eap$PerProviderLimitInput);
}
// 未聚焦且内容为空时显示0
if (!focused && this.eap$PerProviderLimitInput.getValue().trim().isEmpty()) {
this.eap$PerProviderLimitInput.setValue("0");
}
Button ref = eap$SmartDoublingToggle;
if (ref != null) {
int visualWidth = this.eap$PerProviderLimitInput.getWidth() + 4 + this.font.width("_");
int visualHeight = 16;
int padding = 2;
int ex = ref.getX() - visualWidth - 5 - padding ;
int ey = ref.getY() + (ref.getHeight() - visualHeight) / 2 - padding + 6;
this.eap$PerProviderLimitInput.setX(ex + padding);
this.eap$PerProviderLimitInput.setY(ey + padding);
this.eap$inputBgX = ex;
this.eap$inputBgY = ey;
this.eap$inputBgW = visualWidth + padding * 2;
this.eap$inputBgH = visualHeight + padding * 2;
}
String cur = this.eap$PerProviderLimitInput.getValue();
if (cur.isBlank()) cur = "0";
this.eap$PerProviderLimitInput.setTooltipMessage(Collections.singletonList(Component.translatable("gui.extendedae_plus.per_provider_limit.tooltip", cur)));
} else {
// 智能翻倍未启用时移除输入框
this.removeWidget(this.eap$PerProviderLimitInput);
}
}
// 每帧刷新仅从菜单(@GuiSync)同步布尔值保持按钮状态一致
@Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false)
private void eap$updateAdvancedBlocking(CallbackInfo ci) {
@ -51,6 +132,8 @@ public abstract class PatternProviderSmartFeaturesMixin<C extends PatternProvide
this.eap$AdvancedBlockingToggle.set(sync.eap$getAdvancedBlockingSynced());
}
eap$updateLimitInput();
if ((Object) this instanceof GuiExPatternProvider) {
try {
((IExPatternButton) this).eap$updateButtonsLayout();
@ -59,4 +142,14 @@ public abstract class PatternProviderSmartFeaturesMixin<C extends PatternProvide
}
}
}
@Override
public void eap$renderInputBackground(GuiGraphics guiGraphics) {
if (this.eap$SmartDoublingToggle != null && this.eap$SmartDoublingToggle.getCurrentValue() == YesNo.YES
&& this.eap$PerProviderLimitInput != null && this.eap$PerProviderLimitInput.isVisible()) {
Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter()
.dest(this.eap$inputBgX - 5, this.eap$inputBgY-3, this.eap$inputBgW + 6, this.eap$inputBgH- 2)
.blit(guiGraphics);
}
}
}

View File

@ -10,11 +10,14 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.util.ConfigManager;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.util.smartDoubling.PatternScaler;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import org.spongepowered.asm.mixin.Final;
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;
@ -22,9 +25,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(value = PatternProviderLogic.class, remap = false)
public class PatternProviderLogicDoublingMixin {
public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder {
@Unique private static final String EAP_PROVIDER_SCALING_LIMIT = "eap_provider_scaling_limit";
@Shadow @Final private List<IPatternDetails> patterns;
@Shadow @Final private IConfigManager configManager;
@Unique private int eap$providerScalingLimit = 0; // 供应器级别的上限0 表示不限制
@Shadow
public IConfigManager getConfigManager() {return null;}
@ -32,11 +37,24 @@ public class PatternProviderLogicDoublingMixin {
@Shadow
public void updatePatterns() {}
@Override
public int eap$getProviderSmartDoublingLimit() {
return this.eap$providerScalingLimit;
}
@Override
public void eap$setProviderSmartDoublingLimit(int limit) {
this.eap$providerScalingLimit = limit;
this.updatePatterns();
}
@Inject(
method = "<init>(Lappeng/api/networking/IManagedGridNode;Lappeng/helpers/patternprovider/PatternProviderLogicHost;I)V",
at = @At("TAIL")
)
private void onInitTail(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
private void onInitTail(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize,
CallbackInfo ci) {
// 直接往构建后的 configManager 里加 setting
ConfigManager configManager = (ConfigManager) this.getConfigManager();
configManager.registerSetting(EAPSettings.SMART_DOUBLING, YesNo.NO);
@ -49,24 +67,37 @@ public class PatternProviderLogicDoublingMixin {
}
}
@Inject(method = "writeToNBT", at = @At("TAIL"))
private void eap$writeSmartDoublingToNbt(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
// 保存供应器级别上限
tag.putInt(EAP_PROVIDER_SCALING_LIMIT, this.eap$providerScalingLimit);
}
@Inject(method = "readFromNBT", at = @At("TAIL"))
private void eap$readSmartDoublingFromNbt(CompoundTag tag, HolderLookup.Provider registries, CallbackInfo ci) {
// TODO
// 适配旧版本中的数据后续版本删除
if (tag.contains("epp_smart_doubling")) {
this.configManager.putSetting(EAPSettings.SMART_DOUBLING,
tag.getBoolean("epp_smart_doubling") ? YesNo.YES : YesNo.NO);
tag.getBoolean("epp_smart_doubling") ? YesNo.YES : YesNo.NO
);
tag.remove("epp_smart_doubling");
}
if (tag.contains(EAP_PROVIDER_SCALING_LIMIT)) {
this.eap$providerScalingLimit = tag.getInt(EAP_PROVIDER_SCALING_LIMIT);
}
}
@Inject(method = "updatePatterns", at = @At("TAIL"))
private void eap$applySmartDoublingToPatterns(CallbackInfo ci) {
IConfigManager configManager = this.getConfigManager();
boolean allowScaling = configManager.getSetting(EAPSettings.SMART_DOUBLING) == YesNo.YES;
int limit = this.eap$providerScalingLimit;
for (IPatternDetails details : this.patterns) {
if (details instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allowScaling);
aware.eap$setMultiplierLimit(PatternScaler.getComputedMul(details, limit));
}
}
}

View File

@ -6,6 +6,7 @@ import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -18,11 +19,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class PatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Shadow @Final protected PatternProviderLogic logic;
@Unique @GuiSync(21) private YesNo eap$SmartDoubling;
@Unique @GuiSync(22) public int eap$PerProviderScalingLimit = 0; // 0 = no limit
@Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((PatternProviderMenu) (Object) this).isClientSide()) {
this.eap$SmartDoubling = this.logic.getConfigManager().getSetting(EAPSettings.SMART_DOUBLING);
var l = this.logic;
this.eap$SmartDoubling = l.getConfigManager().getSetting(EAPSettings.SMART_DOUBLING);
if (l instanceof ISmartDoublingHolder holder) {
this.eap$PerProviderScalingLimit = holder.eap$getProviderSmartDoublingLimit();
}
}
}
@ -30,4 +36,9 @@ public abstract class PatternProviderMenuDoublingMixin implements IPatternProvid
public YesNo eap$getSmartDoublingSynced() {
return this.eap$SmartDoubling;
}
@Override
public int eap$getScalingLimit() {
return this.eap$PerProviderScalingLimit;
}
}

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.network;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAccessor;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.util.PatternProviderDataUtil;
import net.minecraft.network.FriendlyByteBuf;
@ -50,7 +50,7 @@ public class ScalePatternsC2SPacket implements CustomPacketPayload {
if (!(player.containerMenu instanceof PatternProviderMenu menu)) return;
try {
var accessor = (PatternProviderMenuAdvancedAccessor) menu;
var accessor = (PatternProviderMenuAccessor) menu;
PatternProviderLogic logic = accessor.eap$logic();
if (logic == null) return;

View File

@ -0,0 +1,71 @@
package com.extendedae_plus.network;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAccessor;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu;
/**
* C2S: set per-provider scaling limit for the currently opened provider and pattern index
*/
public class SetPerProviderScalingLimitC2SPacket implements CustomPacketPayload {
private final int limit;
public static final CustomPacketPayload.Type<SetPerProviderScalingLimitC2SPacket> TYPE = new CustomPacketPayload.Type<>(
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "set_per_provider_scaling_limit"));
public SetPerProviderScalingLimitC2SPacket(int limit) {
this.limit = limit;
}
public int limit() { return limit; }
public static final StreamCodec<RegistryFriendlyByteBuf, SetPerProviderScalingLimitC2SPacket> STREAM_CODEC = StreamCodec.of(
(buf, pkt) -> {
buf.writeInt(pkt.limit);
},
buf -> new SetPerProviderScalingLimitC2SPacket(buf.readInt())
);
@Override
public CustomPacketPayload.Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final SetPerProviderScalingLimitC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> {
try {
if (!(ctx.player() instanceof ServerPlayer player)) {
return;
}
var containerMenu = player.containerMenu;
if (containerMenu instanceof PatternProviderMenu menu) {
var accessor = (PatternProviderMenuAccessor) menu;
var logic = accessor.eap$logic();
if (logic instanceof ISmartDoublingHolder handler) {
handler.eap$setProviderSmartDoublingLimit(msg.limit);
logic.saveChanges();
}
} else if (containerMenu instanceof AdvPatternProviderMenu advMenu) {
var accessor = (AdvPatternProviderMenuAdvancedAccessor) advMenu;
var logic = accessor.eap$logic();
if (logic instanceof ISmartDoublingHolder handler) {
handler.eap$setProviderSmartDoublingLimit(msg.limit);
logic.saveChanges();
}
}
} catch (Throwable ignored) {
}
});
}
}

View File

@ -4,14 +4,19 @@ import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.stacks.GenericStack;
import appeng.client.gui.me.patternaccess.PatternContainerRecord;
import appeng.client.gui.me.patternaccess.PatternSlot;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.AETextField;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.Component;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import java.util.List;
import java.util.Set;
import java.util.function.IntConsumer;
/**
@ -187,4 +192,30 @@ public class GuiUtil {
int backgroundColor = withAlpha(rainbowRgb, 0x3C);
drawSlotBox(guiGraphics, sx, sy, borderColor, backgroundColor);
}
/**
* 创建用于每个提供者缩放上限的输入框使用 AE2 原生样式
* @param style ScreenStyle 用于获取颜色配置
* @param font 字体对象
* @param initialValue 初始数值
* @param onCommit 当值解析成功后回调 int 形式提供
*/
public static AETextField createPerProviderLimitInput(ScreenStyle style, Font font, int initialValue, IntConsumer onCommit) {
// 高度设为16与按钮高度(16)一致内部会减去4px padding实际渲染高度12
AETextField input = new AETextField(style, font, 0, 0, 32, 16);
input.setMaxLength(6);
input.setBordered(false);
input.setValue(String.valueOf(initialValue));
input.setResponder(s -> {
try {
String sValue = (s == null || s.isBlank()) ? "0" : s.replaceFirst("^0+(?=.)", "");
if (!sValue.equals(s)) {
input.setValue(sValue);
}
int limit = Integer.parseInt(sValue);
onCommit.accept(limit);
} catch (Throwable ignored) {}
});
return input;
}
}

View File

@ -4,7 +4,6 @@ import appeng.api.crafting.IPatternDetails;
import appeng.api.stacks.AEFluidKey;
import appeng.api.stacks.AEItemKey;
import appeng.api.stacks.AEKey;
import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.crafting.ScaledProcessingPatternAdv;
import net.neoforged.fml.loading.LoadingModList;
@ -48,7 +47,7 @@ public final class PatternScaler {
* 创建缩放样板
* 自动支持原版 AE 和可选 AAE AdvProcessingPattern
*/
public static IPatternDetails createScaled(IPatternDetails base, long multiplier) {
public static ScaledProcessingPattern createScaled(IPatternDetails base, long multiplier) {
// 尝试 Advanced AE 扩展
if (advAvailable && advIfaceClass != null && advCtor != null) {
try {
@ -67,7 +66,7 @@ public final class PatternScaler {
/**
* 计算基于 limit 的最大允许倍率单次输出主物品 limit
*/
public static int getComputedMul(AEProcessingPattern proc, int limit) {
public static int getComputedMul(IPatternDetails proc, int limit) {
if (limit <= 0) return 0; // 0 = 不限制
long minMul = Long.MAX_VALUE;

View File

@ -6,6 +6,7 @@
"gui.extendedae_plus.global.toggle_blocking": "Toggle Blocking Mode",
"gui.extendedae_plus.global.toggle_adv_blocking": "Toggle Advanced Blocking",
"gui.extendedae_plus.global.toggle_smart_doubling": "Toggle Smart Doubling",
"gui.extendedae_plus.per_provider_limit.tooltip": "Per-item distribution limit: %s",
"gui.extendedae_plus.global.all_on": "All On",
"gui.extendedae_plus.global.all_off": "All Off",

View File

@ -6,6 +6,7 @@
"gui.extendedae_plus.global.toggle_blocking": "切换阻挡模式",
"gui.extendedae_plus.global.toggle_adv_blocking": "切换高级阻挡",
"gui.extendedae_plus.global.toggle_smart_doubling": "切换智能翻倍",
"gui.extendedae_plus.per_provider_limit.tooltip": "单样物品发配数量上限: %s",
"gui.extendedae_plus.global.all_on": "全部开启",
"gui.extendedae_plus.global.all_off": "全部关闭",

View File

@ -9,11 +9,11 @@
"advancedae.accessor.AdvCraftingCPUAccessor",
"advancedae.accessor.AdvCraftingCPULogicAccessor",
"advancedae.accessor.AdvExecutingCraftingJobAccessor",
"advancedae.crafting.AdvCraftingCPULogicManualWaitingMixin",
"advancedae.accessor.AdvExecutingCraftingJobTaskProgressAccessor",
"advancedae.accessor.AdvPatternProviderLogicPatternsAccessor",
"advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor",
"advancedae.compat.PatternProviderLogicVirtualCompletionMixin",
"advancedae.crafting.AdvCraftingCPULogicManualWaitingMixin",
"advancedae.helpers.AdvPatternProviderLogicAdvancedMixin",
"advancedae.helpers.AdvPatternProviderLogicDoublingMixin",
"advancedae.menu.AdvPatternProviderMenuAdvancedMixin",
@ -32,7 +32,7 @@
"ae2.accessor.PatternProviderLogicAccessor",
"ae2.accessor.PatternProviderLogicPatternInputsAccessor",
"ae2.accessor.PatternProviderLogicPatternsAccessor",
"ae2.accessor.PatternProviderMenuAdvancedAccessor",
"ae2.accessor.PatternProviderMenuAccessor",
"ae2.autopattern.CraftingCalculationMixin",
"ae2.autopattern.CraftingServiceGetProvidersMixin",
"ae2.autopattern.CraftingSimulationStateAccessor",
@ -40,6 +40,7 @@
"ae2.autopattern.PatternProviderLogicContainsRedirectMixin",
"ae2.compat.PatternProviderLogicCompatMixin",
"ae2.compat.PatternProviderLogicVirtualCompletionMixin",
"ae2.crafting.CraftingCpuLogicManualWaitingMixin",
"ae2.helpers.InterfaceLogicChannelCardMixin",
"ae2.helpers.InterfaceLogicTickerMixin",
"ae2.helpers.InterfaceLogicUpgradesMixin",
@ -49,16 +50,15 @@
"ae2.helpers.PatternProviderLogicUpgradesMixin",
"ae2.helpers.patternprovider.PatternProviderLogicTickerMixin",
"ae2.menu.AEBaseMenuUpgradesDedupMixin",
"ae2.menu.ContainerPatternEncodingTermMenuMixin",
"ae2.menu.CraftConfirmMenuForceStartMixin",
"ae2.menu.CraftingCPUMenuManualStatusMixin",
"ae2.menu.ContainerPatternEncodingTermMenuMixin",
"ae2.menu.MEStorageMenuMixin",
"ae2.menu.PatternEncodingTermMenuMixin",
"ae2.menu.PatternProviderMenuAdvancedMixin",
"ae2.menu.PatternProviderMenuDoublingMixin",
"ae2.menu.PatternProviderMenuUpgradesMixin",
"ae2.network.PatternAccessTerminalPacketMixin",
"ae2.crafting.CraftingCpuLogicManualWaitingMixin",
"ae2.parts.automation.IOBusPartChannelCardMixin",
"ae2.parts.storagebus.StorageBusPartChannelCardMixin",
"ae2WTlib.ContainerUWirelessExPatternTerminalMixin",