From 60be80c397c1c1f93d6ae9c4f6b3634d8f7bbe47 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 2 Jun 2026 19:37:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=A0=B7=E6=9D=BF?= =?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=99=A8=E7=BA=A7=E5=88=AB=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E7=BF=BB=E5=80=8D=E9=99=90=E5=88=B6=20fix:=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Daae=E9=AB=98=E7=BA=A7=E6=A0=B7=E6=9D=BF=E4=B8=8D?= =?UTF-8?q?=E7=94=9F=E6=95=88=E6=99=BA=E8=83=BD=E7=BF=BB=E5=80=8D=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/IInputBackgroundRenderer.java | 14 +++ .../IPatternProviderMenuDoublingSync.java | 2 + .../api/smartDoubling/ISmartDoubling.java | 6 -- .../smartDoubling/ISmartDoublingHolder.java | 7 ++ .../com/extendedae_plus/init/ModNetwork.java | 19 +++- .../AdvPatternProviderSmartFeaturesMixin.java | 96 +++++++++++++++++- .../SmallAdvPatternProviderScreenMixin.java | 96 +++++++++++++++++- .../AdvPatternProviderLogicDoublingMixin.java | 33 ++++++- .../AdvPatternProviderMenuDoublingMixin.java | 13 ++- ....java => PatternProviderMenuAccessor.java} | 2 +- .../CraftingSimulationStateMixin.java | 34 ++++--- .../ae2/client/gui/AEBaseScreenMixin.java | 10 ++ .../PatternProviderSmartFeaturesMixin.java | 97 ++++++++++++++++++- .../PatternProviderLogicDoublingMixin.java | 37 ++++++- .../PatternProviderMenuDoublingMixin.java | 13 ++- .../network/ScalePatternsC2SPacket.java | 4 +- .../SetPerProviderScalingLimitC2SPacket.java | 71 ++++++++++++++ .../com/extendedae_plus/util/GuiUtil.java | 31 ++++++ .../util/smartDoubling/PatternScaler.java | 5 +- .../assets/extendedae_plus/lang/en_us.json | 1 + .../assets/extendedae_plus/lang/zh_cn.json | 1 + .../resources/extendedae_plus.mixins.json | 8 +- 22 files changed, 554 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/api/IInputBackgroundRenderer.java delete mode 100644 src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoubling.java create mode 100644 src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingHolder.java rename src/main/java/com/extendedae_plus/mixin/ae2/accessor/{PatternProviderMenuAdvancedAccessor.java => PatternProviderMenuAccessor.java} (86%) create mode 100644 src/main/java/com/extendedae_plus/network/SetPerProviderScalingLimitC2SPacket.java diff --git a/src/main/java/com/extendedae_plus/api/IInputBackgroundRenderer.java b/src/main/java/com/extendedae_plus/api/IInputBackgroundRenderer.java new file mode 100644 index 0000000..30cf712 --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/IInputBackgroundRenderer.java @@ -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); +} diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/IPatternProviderMenuDoublingSync.java b/src/main/java/com/extendedae_plus/api/smartDoubling/IPatternProviderMenuDoublingSync.java index 437d649..b6edf7a 100644 --- a/src/main/java/com/extendedae_plus/api/smartDoubling/IPatternProviderMenuDoublingSync.java +++ b/src/main/java/com/extendedae_plus/api/smartDoubling/IPatternProviderMenuDoublingSync.java @@ -4,4 +4,6 @@ import appeng.api.config.YesNo; public interface IPatternProviderMenuDoublingSync { YesNo eap$getSmartDoublingSynced(); + + int eap$getScalingLimit(); } diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoubling.java b/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoubling.java deleted file mode 100644 index 8e36f4e..0000000 --- a/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoubling.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.extendedae_plus.api.smartDoubling; - -public interface ISmartDoubling { - boolean eap$getSmartDoubling(); - void eap$setSmartDoubling(boolean value); -} diff --git a/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingHolder.java b/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingHolder.java new file mode 100644 index 0000000..b8f4cc7 --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/smartDoubling/ISmartDoublingHolder.java @@ -0,0 +1,7 @@ +package com.extendedae_plus.api.smartDoubling; + +public interface ISmartDoublingHolder { + int eap$getProviderSmartDoublingLimit(); + + void eap$setProviderSmartDoublingLimit(int limit); +} diff --git a/src/main/java/com/extendedae_plus/init/ModNetwork.java b/src/main/java/com/extendedae_plus/init/ModNetwork.java index 4d79aa1..c7ca008 100644 --- a/src/main/java/com/extendedae_plus/init/ModNetwork.java +++ b/src/main/java/com/extendedae_plus/init/ModNetwork.java @@ -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); } } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderSmartFeaturesMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderSmartFeaturesMixin.java index 28060ae..70beb01 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderSmartFeaturesMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderSmartFeaturesMixin.java @@ -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 { +public abstract class AdvPatternProviderSmartFeaturesMixin extends AEBaseScreen implements IInputBackgroundRenderer { @Unique private EAPServerSettingToggleButton eap$AdvancedBlockingToggle; @Unique private EAPServerSettingToggleButton 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); + } } } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java index 91a853c..afdc3c8 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java @@ -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 { +public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen implements IInputBackgroundRenderer { @Unique private EAPServerSettingToggleButton eap$AdvancedBlockingToggle; @Unique private EAPServerSettingToggleButton 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(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 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 = "(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)); } } } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java index 86b4a08..ea69d17 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java @@ -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; + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAccessor.java similarity index 86% rename from src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java rename to src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAccessor.java index 0a0234d..115e7f2 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAccessor.java @@ -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(); } 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 a42e898..a2bd28c 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,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 providerCountCache = new HashMap<>(); for (Map.Entry 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); } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java index 4973615..c536dc5 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java @@ -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); + } + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderSmartFeaturesMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderSmartFeaturesMixin.java index 9c557e5..7ab8bdc 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderSmartFeaturesMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderSmartFeaturesMixin.java @@ -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 extends AEBaseScreen { +public abstract class PatternProviderSmartFeaturesMixin extends AEBaseScreen implements IInputBackgroundRenderer { @Unique private EAPServerSettingToggleButton eap$AdvancedBlockingToggle; @Unique private EAPServerSettingToggleButton 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(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 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 = "(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)); } } } 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 6110b3e..3449f87 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 @@ -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; + } } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/network/ScalePatternsC2SPacket.java b/src/main/java/com/extendedae_plus/network/ScalePatternsC2SPacket.java index 4d5080c..b251a64 100644 --- a/src/main/java/com/extendedae_plus/network/ScalePatternsC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/ScalePatternsC2SPacket.java @@ -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; diff --git a/src/main/java/com/extendedae_plus/network/SetPerProviderScalingLimitC2SPacket.java b/src/main/java/com/extendedae_plus/network/SetPerProviderScalingLimitC2SPacket.java new file mode 100644 index 0000000..42883e8 --- /dev/null +++ b/src/main/java/com/extendedae_plus/network/SetPerProviderScalingLimitC2SPacket.java @@ -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 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 STREAM_CODEC = StreamCodec.of( + (buf, pkt) -> { + buf.writeInt(pkt.limit); + }, + buf -> new SetPerProviderScalingLimitC2SPacket(buf.readInt()) + ); + + @Override + public CustomPacketPayload.Type 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) { + } + }); + } +} + + diff --git a/src/main/java/com/extendedae_plus/util/GuiUtil.java b/src/main/java/com/extendedae_plus/util/GuiUtil.java index 3e202be..c0b1d71 100644 --- a/src/main/java/com/extendedae_plus/util/GuiUtil.java +++ b/src/main/java/com/extendedae_plus/util/GuiUtil.java @@ -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; + } } \ No newline at end of file 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 c1aba28..9c6f0a9 100644 --- a/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java +++ b/src/main/java/com/extendedae_plus/util/smartDoubling/PatternScaler.java @@ -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; diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 28b3577..3d9df6e 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -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", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 71f74f4..22256ca 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -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": "全部关闭", diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index 5e12244..478e43f 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -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",