diff --git a/build.gradle b/build.gradle index df22770..2436a25 100644 --- a/build.gradle +++ b/build.gradle @@ -129,10 +129,8 @@ dependencies { modRuntimeOnly "curse.maven:ftb-library-forge-404465:6807424" } -allprojects { - tasks.withType(JavaCompile).configureEach { - options.compilerArgs << "-Xlint:-deprecation" - } +compileJava { + options.compilerArgs += ['-Xlint:-deprecation', '-Xlint:-removal', '-Xlint:-unchecked'] } processResources { diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java index 2b4af58..3e5120d 100644 --- a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java +++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java @@ -17,8 +17,10 @@ import net.minecraftforge.registries.ForgeRegistries; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; +import java.math.BigInteger; import java.util.List; import java.util.Objects; +import java.util.UUID; public class InfinityBigIntegerCellItem extends Item implements ICellWorkbenchItem { @@ -59,7 +61,7 @@ public class InfinityBigIntegerCellItem extends Item implements ICellWorkbenchIt if (tag.contains(InfinityConstants.INFINITY_ITEM_TOTAL)) { try { byte[] bytes = tag.getByteArray(InfinityConstants.INFINITY_ITEM_TOTAL); - java.math.BigInteger total = new java.math.BigInteger(bytes); + BigInteger total = new BigInteger(bytes); String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total); tooltip.add( Component.literal("Total: ").withStyle(ChatFormatting.GRAY).append(Component.literal(formatted).withStyle(ChatFormatting.AQUA)) @@ -70,7 +72,7 @@ public class InfinityBigIntegerCellItem extends Item implements ICellWorkbenchIt } else if (tag.contains(InfinityConstants.INFINITY_CELL_ITEM_COUNT)) { try { byte[] bytes = tag.getByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT); - java.math.BigInteger total = new java.math.BigInteger(bytes); + BigInteger total = new BigInteger(bytes); String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total); tooltip.add( Component.literal("Total: ").withStyle(ChatFormatting.GRAY).append(Component.literal(formatted).withStyle(ChatFormatting.AQUA)) @@ -85,7 +87,7 @@ public class InfinityBigIntegerCellItem extends Item implements ICellWorkbenchIt /** * 创建一个带有指定 UUID 的 Infinity 磁盘 ItemStack */ - public static ItemStack withUUID(java.util.UUID uuid) { + public static ItemStack withUUID(UUID uuid) { ItemStack stack = new ItemStack(Objects.requireNonNull( ForgeRegistries.ITEMS.getValue(new ResourceLocation("extendedae_plus", "infinity_biginteger_cell") ))); diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java index cbefdde..065b503 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java @@ -5,13 +5,15 @@ import appeng.api.config.YesNo; import appeng.client.gui.AEBaseScreen; import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.widgets.SettingToggleButton; -import com.extendedae_plus.api.IExPatternButtonsAccessor; import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync; import com.extendedae_plus.init.ModNetwork; +import com.extendedae_plus.network.provider.SetPerProviderScalingLimitC2SPacket; import com.extendedae_plus.network.provider.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.provider.ToggleSmartDoublingC2SPacket; -import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Tooltip; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.pedroksl.advanced_ae.client.gui.AdvPatternProviderScreen; @@ -22,6 +24,9 @@ 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.List; +import java.util.function.Supplier; + import static com.extendedae_plus.util.Logger.EAP$LOGGER; /** @@ -31,116 +36,209 @@ import static com.extendedae_plus.util.Logger.EAP$LOGGER; */ @Mixin(AdvPatternProviderScreen.class) public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen { + // 高级阻挡模式切换按钮 + @Unique private SettingToggleButton eap$AdvancedBlockingToggle; + // 智能翻倍切换按钮 + @Unique private SettingToggleButton eap$SmartDoublingToggle; + // 智能翻倍上限输入框 + @Unique private EditBox eap$PerProviderLimitInput; - @Unique - private SettingToggleButton eap$AdvancedBlockingToggle; - - @Unique - private boolean eap$AdvancedBlockingEnabled = false; - - @Unique - private SettingToggleButton eap$SmartDoublingToggle; - - @Unique - private boolean eap$SmartDoublingEnabled = false; + // 当前高级阻挡模式是否启用 + @Unique private boolean eap$AdvancedBlockingEnabled = false; + // 当前智能翻倍是否启用 + @Unique private boolean eap$SmartDoublingEnabled = false; + // 当前智能翻倍上限 + @Unique private int eap$PerProviderScalingLimit = 0; + // 输入框上次是否处于焦点 + @Unique private boolean eap$PerProviderLimitWasFocused = false; public AdvPatternProviderScreenMixin(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) { super(menu, playerInventory, title, style); } - @Inject(method = "", at = @At("RETURN")) - private void eap$initAdvancedBlocking(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { - // 使用 @GuiSync 初始化 + /* ---------------------------- 工具方法 ---------------------------- */ + /** + * 创建一个带有自定义点击事件和 tooltip 的切换按钮 + */ + @Unique + private SettingToggleButton eap$createToggle(boolean initial, + Runnable onClick, + Supplier> tooltipSupplier) { + return new SettingToggleButton<>( + Settings.BLOCKING_MODE, + initial ? YesNo.YES : YesNo.NO, + (btn, backwards) -> onClick.run() + ) { + @Override + public List getTooltipMessage() { + return tooltipSupplier.get(); + } + }; + } + + /** 同步服务端状态(初始化时调用) */ + @Unique + private void eap$syncInitialState(AdvPatternProviderMenu menu) { try { + // 同步高级阻挡和智能翻倍的服务端状态 if (menu instanceof IPatternProviderMenuAdvancedSync sync) { this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); } - } catch (Throwable t) { - EAP$LOGGER.error("Error initializing advanced sync", t); - } - - // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” - this.eap$AdvancedBlockingToggle = new SettingToggleButton<>( - Settings.BLOCKING_MODE, - this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, - (btn, backwards) -> { - // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 - ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); - } - ) { - @Override - public java.util.List getTooltipMessage() { - boolean enabled = eap$AdvancedBlockingEnabled; - var title = Component.literal("智能阻挡"); - var line = enabled - ? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") - : Component.literal("已禁用:这么好的功能为什么不打开呢"); - return java.util.List.of(title, line); - } - }; - // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 - this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); - - this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); - - // 智能翻倍按钮:与高级阻挡同款样式,点击仅发送C2S,状态由@GuiSync驱动 - try { - if (menu instanceof IPatternProviderMenuDoublingSync sync2) { - this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); + if (menu instanceof IPatternProviderMenuDoublingSync sync) { + this.eap$SmartDoublingEnabled = sync.eap$getSmartDoublingSynced(); + this.eap$PerProviderScalingLimit = sync.eap$getScalingLimit(); } } catch (Throwable t) { - EAP$LOGGER.error("Error initializing smart doubling sync", t); + EAP$LOGGER.error("Error initializing sync", t); } - - this.eap$SmartDoublingToggle = new SettingToggleButton<>( - Settings.BLOCKING_MODE, - this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO, - (btn, backwards) -> { - ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()); - } - ) { - @Override - public java.util.List getTooltipMessage() { - boolean enabled = eap$SmartDoublingEnabled; - var title = Component.literal("智能翻倍"); - var line = enabled - ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") - : Component.literal("已禁用:按原始样板数量进行发配"); - return java.util.List.of(title, line); - } - }; - - this.eap$SmartDoublingToggle.set(this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); - this.addToLeftToolbar(this.eap$SmartDoublingToggle); } - // 每帧刷新:仅从菜单(@GuiSync)同步布尔值,保持按钮状态一致 + /** 创建并添加按钮和输入框 */ + @Unique + private void eap$createWidgets() { + // 高级阻挡 + this.eap$AdvancedBlockingToggle = eap$createToggle( + eap$AdvancedBlockingEnabled, + () -> ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()), + () -> { + var t = Component.literal("智能阻挡"); + var line = eap$AdvancedBlockingEnabled + ? Component.literal("已启用:对于同一种配方将不再阻挡 (需要启用原版阻挡模式)") + : Component.literal("已禁用:建议开启以获得更智能的阻挡行为"); + return List.of(t, line); + } + ); + this.eap$AdvancedBlockingToggle.set(eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); + + // 智能翻倍 + this.eap$SmartDoublingToggle = eap$createToggle( + eap$SmartDoublingEnabled, + () -> ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()), + () -> { + var t = Component.literal("智能翻倍"); + var line = eap$SmartDoublingEnabled + ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") + : Component.literal("已禁用:按原始样板数量进行发配"); + return List.of(t, line); + } + ); + this.eap$SmartDoublingToggle.set(eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$SmartDoublingToggle); + + // 缩放上限输入框 + this.eap$PerProviderLimitInput = new EditBox(this.font, 0, 0, 28, 12, Component.literal("Limit")); + this.eap$PerProviderLimitInput.setMaxLength(6); + this.eap$PerProviderLimitInput.setValue(String.valueOf(eap$PerProviderScalingLimit)); + this.eap$PerProviderLimitInput.setResponder(this::eap$handleLimitChanged); + this.addRenderableWidget(this.eap$PerProviderLimitInput); + } + + /** 输入框内容变化时调用 */ + @Unique + private void eap$handleLimitChanged(String s) { + try { + // 去除前导0,空字符串视为0 + String sValue = (s == null || s.isBlank()) ? "0" : s.replaceFirst("^0+(?=.)", ""); + if (!sValue.equals(s)) { + this.eap$PerProviderLimitInput.setValue(sValue); + } + int limit = Integer.parseInt(sValue); + // 只有变化时才发送同步包 + if (limit != this.eap$PerProviderScalingLimit) { + this.eap$PerProviderScalingLimit = limit; + ModNetwork.CHANNEL.sendToServer(new SetPerProviderScalingLimitC2SPacket(limit)); + } + } catch (Throwable ignored) {} + } + + /* ---------------------------- 注入点 ---------------------------- */ + @Inject(method = "", at = @At("RETURN")) + private void eap$onInit(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { + // 初始化时同步服务端状态并创建控件 + eap$syncInitialState(menu); + eap$createWidgets(); + } + + /** 每帧刷新:从服务端同步状态并更新 UI */ @Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false) - private void eap$updateAdvancedBlocking(CallbackInfo ci) { - if (this.eap$AdvancedBlockingToggle != null) { - boolean desired = this.eap$AdvancedBlockingEnabled; - if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) { - desired = sync.eap$getAdvancedBlockingSynced(); - } - this.eap$AdvancedBlockingEnabled = desired; - this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); + private void eap$updateBeforeRender(CallbackInfo ci) { + // 每帧刷新按钮和输入框状态 + eap$updateToggles(); + eap$updateLimitInput(); + } + + /* ---------------------------- 刷新逻辑 ---------------------------- */ + /** + * 刷新切换按钮的状态(与服务端同步) + */ + @Unique + private void eap$updateToggles() { + if (this.eap$AdvancedBlockingToggle != null && this.menu instanceof IPatternProviderMenuAdvancedSync sync) { + this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); + this.eap$AdvancedBlockingToggle.set(eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + } + if (this.eap$SmartDoublingToggle != null && this.menu instanceof IPatternProviderMenuDoublingSync sync) { + this.eap$SmartDoublingEnabled = sync.eap$getSmartDoublingSynced(); + this.eap$SmartDoublingToggle.set(eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + } + } + + /** + * 刷新输入框的内容和可见性 + */ + @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(); } - if (this.eap$SmartDoublingToggle != null) { - boolean desired2 = this.eap$SmartDoublingEnabled; - if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) { - desired2 = sync2.eap$getSmartDoublingSynced(); - } - this.eap$SmartDoublingEnabled = desired2; - this.eap$SmartDoublingToggle.set(desired2 ? YesNo.YES : YesNo.NO); + boolean focused = this.eap$PerProviderLimitInput.isFocused(); + // 如果未聚焦且服务端有变化,则同步显示 + if (!focused && remoteLimit != this.eap$PerProviderScalingLimit) { + this.eap$PerProviderScalingLimit = remoteLimit; + this.eap$PerProviderLimitInput.setValue(String.valueOf(remoteLimit)); } - if ((Object) this instanceof GuiExPatternProvider) { - try { - ((IExPatternButtonsAccessor) this).eap$updateButtonsLayout(); - } catch (Throwable t) { - EAP$LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString()); + if (this.eap$SmartDoublingEnabled) { + // 智能翻倍启用时,确保输入框可见 + 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 ex = ref.getX() - this.eap$PerProviderLimitInput.getWidth() - 5; + int ey = ref.getY() + 2; + this.eap$PerProviderLimitInput.setX(ex); + this.eap$PerProviderLimitInput.setY(ey); + } + + // 设置 tooltip + String cur = this.eap$PerProviderLimitInput.getValue(); + if (cur.isBlank()) cur = "0"; + this.eap$PerProviderLimitInput.setTooltip(Tooltip.create(Component.literal("样板输入物品数量上限: " + cur))); + + // 失焦时提交最新值 + boolean focusedNow = this.eap$PerProviderLimitInput.isFocused(); + if (this.eap$PerProviderLimitWasFocused && !focusedNow) { + int value = Integer.parseInt(cur); + this.eap$PerProviderScalingLimit = value; + ModNetwork.CHANNEL.sendToServer(new SetPerProviderScalingLimitC2SPacket(value)); + } + this.eap$PerProviderLimitWasFocused = focusedNow; + } else { + // 智能翻倍未启用时,移除输入框 + this.removeWidget(this.eap$PerProviderLimitInput); } } } 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 95b9c8e..45aaade 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 @@ -5,16 +5,19 @@ import appeng.api.config.YesNo; import appeng.client.gui.AEBaseScreen; import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.widgets.SettingToggleButton; -import com.extendedae_plus.api.IExPatternButtonsAccessor; import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync; import com.extendedae_plus.init.ModNetwork; +import com.extendedae_plus.network.provider.SetPerProviderScalingLimitC2SPacket; import com.extendedae_plus.network.provider.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.provider.ToggleSmartDoublingC2SPacket; -import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Tooltip; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.pedroksl.advanced_ae.client.gui.SmallAdvPatternProviderScreen; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; import net.pedroksl.advanced_ae.gui.advpatternprovider.SmallAdvPatternProviderMenu; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -22,6 +25,9 @@ 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.List; +import java.util.function.Supplier; + import static com.extendedae_plus.util.Logger.EAP$LOGGER; /** @@ -31,116 +37,209 @@ import static com.extendedae_plus.util.Logger.EAP$LOGGER; */ @Mixin(SmallAdvPatternProviderScreen.class) public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen { + // 高级阻挡模式切换按钮 + @Unique private SettingToggleButton eap$AdvancedBlockingToggle; + // 智能翻倍切换按钮 + @Unique private SettingToggleButton eap$SmartDoublingToggle; + // 智能翻倍上限输入框 + @Unique private EditBox eap$PerProviderLimitInput; - @Unique - private SettingToggleButton eap$AdvancedBlockingToggle; - - @Unique - private boolean eap$AdvancedBlockingEnabled = false; - - @Unique - private SettingToggleButton eap$SmartDoublingToggle; - - @Unique - private boolean eap$SmartDoublingEnabled = false; + // 当前高级阻挡模式是否启用 + @Unique private boolean eap$AdvancedBlockingEnabled = false; + // 当前智能翻倍是否启用 + @Unique private boolean eap$SmartDoublingEnabled = false; + // 当前智能翻倍上限 + @Unique private int eap$PerProviderScalingLimit = 0; + // 输入框上次是否处于焦点 + @Unique private boolean eap$PerProviderLimitWasFocused = false; public SmallAdvPatternProviderScreenMixin(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) { super(menu, playerInventory, title, style); } - @Inject(method = "", at = @At("RETURN")) - private void eap$initAdvancedBlocking(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { - // 使用 @GuiSync 初始化 + /* ---------------------------- 工具方法 ---------------------------- */ + /** + * 创建一个带有自定义点击事件和 tooltip 的切换按钮 + */ + @Unique + private SettingToggleButton eap$createToggle(boolean initial, + Runnable onClick, + Supplier> tooltipSupplier) { + return new SettingToggleButton<>( + Settings.BLOCKING_MODE, + initial ? YesNo.YES : YesNo.NO, + (btn, backwards) -> onClick.run() + ) { + @Override + public List getTooltipMessage() { + return tooltipSupplier.get(); + } + }; + } + + /** 同步服务端状态(初始化时调用) */ + @Unique + private void eap$syncInitialState(AdvPatternProviderMenu menu) { try { + // 同步高级阻挡和智能翻倍的服务端状态 if (menu instanceof IPatternProviderMenuAdvancedSync sync) { this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); } - } catch (Throwable t) { - EAP$LOGGER.error("Error initializing advanced sync", t); - } - - // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” - this.eap$AdvancedBlockingToggle = new SettingToggleButton<>( - Settings.BLOCKING_MODE, - this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, - (btn, backwards) -> { - // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 - ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); - } - ) { - @Override - public java.util.List getTooltipMessage() { - boolean enabled = eap$AdvancedBlockingEnabled; - var title = Component.literal("智能阻挡"); - var line = enabled - ? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") - : Component.literal("已禁用:这么好的功能为什么不打开呢"); - return java.util.List.of(title, line); - } - }; - // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 - this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); - - this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); - - // 智能翻倍按钮:与高级阻挡同款样式,点击仅发送C2S,状态由@GuiSync驱动 - try { - if (menu instanceof IPatternProviderMenuDoublingSync sync2) { - this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); + if (menu instanceof IPatternProviderMenuDoublingSync sync) { + this.eap$SmartDoublingEnabled = sync.eap$getSmartDoublingSynced(); + this.eap$PerProviderScalingLimit = sync.eap$getScalingLimit(); } } catch (Throwable t) { - EAP$LOGGER.error("Error initializing smart doubling sync", t); + EAP$LOGGER.error("Error initializing sync", t); } - - this.eap$SmartDoublingToggle = new SettingToggleButton<>( - Settings.BLOCKING_MODE, - this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO, - (btn, backwards) -> { - ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()); - } - ) { - @Override - public java.util.List getTooltipMessage() { - boolean enabled = eap$SmartDoublingEnabled; - var title = Component.literal("智能翻倍"); - var line = enabled - ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") - : Component.literal("已禁用:按原始样板数量进行发配"); - return java.util.List.of(title, line); - } - }; - - this.eap$SmartDoublingToggle.set(this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); - this.addToLeftToolbar(this.eap$SmartDoublingToggle); } - // 每帧刷新:仅从菜单(@GuiSync)同步布尔值,保持按钮状态一致 + /** 创建并添加按钮和输入框 */ + @Unique + private void eap$createWidgets() { + // 高级阻挡 + this.eap$AdvancedBlockingToggle = eap$createToggle( + eap$AdvancedBlockingEnabled, + () -> ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()), + () -> { + var t = Component.literal("智能阻挡"); + var line = eap$AdvancedBlockingEnabled + ? Component.literal("已启用:对于同一种配方将不再阻挡 (需要启用原版阻挡模式)") + : Component.literal("已禁用:建议开启以获得更智能的阻挡行为"); + return List.of(t, line); + } + ); + this.eap$AdvancedBlockingToggle.set(eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); + + // 智能翻倍 + this.eap$SmartDoublingToggle = eap$createToggle( + eap$SmartDoublingEnabled, + () -> ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()), + () -> { + var t = Component.literal("智能翻倍"); + var line = eap$SmartDoublingEnabled + ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") + : Component.literal("已禁用:按原始样板数量进行发配"); + return List.of(t, line); + } + ); + this.eap$SmartDoublingToggle.set(eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$SmartDoublingToggle); + + // 缩放上限输入框 + this.eap$PerProviderLimitInput = new EditBox(this.font, 0, 0, 28, 12, Component.literal("Limit")); + this.eap$PerProviderLimitInput.setMaxLength(6); + this.eap$PerProviderLimitInput.setValue(String.valueOf(eap$PerProviderScalingLimit)); + this.eap$PerProviderLimitInput.setResponder(this::eap$handleLimitChanged); + this.addRenderableWidget(this.eap$PerProviderLimitInput); + } + + /** 输入框内容变化时调用 */ + @Unique + private void eap$handleLimitChanged(String s) { + try { + // 去除前导0,空字符串视为0 + String sValue = (s == null || s.isBlank()) ? "0" : s.replaceFirst("^0+(?=.)", ""); + if (!sValue.equals(s)) { + this.eap$PerProviderLimitInput.setValue(sValue); + } + int limit = Integer.parseInt(sValue); + // 只有变化时才发送同步包 + if (limit != this.eap$PerProviderScalingLimit) { + this.eap$PerProviderScalingLimit = limit; + ModNetwork.CHANNEL.sendToServer(new SetPerProviderScalingLimitC2SPacket(limit)); + } + } catch (Throwable ignored) {} + } + + /* ---------------------------- 注入点 ---------------------------- */ + @Inject(method = "", at = @At("RETURN")) + private void eap$onInit(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { + // 初始化时同步服务端状态并创建控件 + eap$syncInitialState(menu); + eap$createWidgets(); + } + + /** 每帧刷新:从服务端同步状态并更新 UI */ @Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false) - private void eap$updateAdvancedBlocking(CallbackInfo ci) { - if (this.eap$AdvancedBlockingToggle != null) { - boolean desired = this.eap$AdvancedBlockingEnabled; - if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) { - desired = sync.eap$getAdvancedBlockingSynced(); - } - this.eap$AdvancedBlockingEnabled = desired; - this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); + private void eap$updateBeforeRender(CallbackInfo ci) { + // 每帧刷新按钮和输入框状态 + eap$updateToggles(); + eap$updateLimitInput(); + } + + /* ---------------------------- 刷新逻辑 ---------------------------- */ + /** + * 刷新切换按钮的状态(与服务端同步) + */ + @Unique + private void eap$updateToggles() { + if (this.eap$AdvancedBlockingToggle != null && this.menu instanceof IPatternProviderMenuAdvancedSync sync) { + this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); + this.eap$AdvancedBlockingToggle.set(eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + } + if (this.eap$SmartDoublingToggle != null && this.menu instanceof IPatternProviderMenuDoublingSync sync) { + this.eap$SmartDoublingEnabled = sync.eap$getSmartDoublingSynced(); + this.eap$SmartDoublingToggle.set(eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + } + } + + /** + * 刷新输入框的内容和可见性 + */ + @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(); } - if (this.eap$SmartDoublingToggle != null) { - boolean desired2 = this.eap$SmartDoublingEnabled; - if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) { - desired2 = sync2.eap$getSmartDoublingSynced(); - } - this.eap$SmartDoublingEnabled = desired2; - this.eap$SmartDoublingToggle.set(desired2 ? YesNo.YES : YesNo.NO); + boolean focused = this.eap$PerProviderLimitInput.isFocused(); + // 如果未聚焦且服务端有变化,则同步显示 + if (!focused && remoteLimit != this.eap$PerProviderScalingLimit) { + this.eap$PerProviderScalingLimit = remoteLimit; + this.eap$PerProviderLimitInput.setValue(String.valueOf(remoteLimit)); } - if ((Object) this instanceof GuiExPatternProvider) { - try { - ((IExPatternButtonsAccessor) this).eap$updateButtonsLayout(); - } catch (Throwable t) { - EAP$LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString()); + if (this.eap$SmartDoublingEnabled) { + // 智能翻倍启用时,确保输入框可见 + 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 ex = ref.getX() - this.eap$PerProviderLimitInput.getWidth() - 5; + int ey = ref.getY() + 2; + this.eap$PerProviderLimitInput.setX(ex); + this.eap$PerProviderLimitInput.setY(ey); + } + + // 设置 tooltip + String cur = this.eap$PerProviderLimitInput.getValue(); + if (cur.isBlank()) cur = "0"; + this.eap$PerProviderLimitInput.setTooltip(Tooltip.create(Component.literal("样板输入物品数量上限: " + cur))); + + // 失焦时提交最新值 + boolean focusedNow = this.eap$PerProviderLimitInput.isFocused(); + if (this.eap$PerProviderLimitWasFocused && !focusedNow) { + int value = Integer.parseInt(cur); + this.eap$PerProviderScalingLimit = value; + ModNetwork.CHANNEL.sendToServer(new SetPerProviderScalingLimitC2SPacket(value)); + } + this.eap$PerProviderLimitWasFocused = focusedNow; + } else { + // 智能翻倍未启用时,移除输入框 + this.removeWidget(this.eap$PerProviderLimitInput); } } } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java index c123a51..27c6622 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java @@ -17,11 +17,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = AdvPatternProviderLogic.class, remap = false) public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolder { - @Unique - private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling"; + @Unique private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling"; + @Unique private static final String EAP_PROVIDER_SCALING_LIMIT = "eap_provider_scaling_limit"; - @Unique - private boolean eap$smartDoubling = false; + @Unique private boolean eap$smartDoubling = false; + @Unique private int eap$providerScalingLimit = 0; // 供应器级别的上限,0 表示不限制 @Override public boolean eap$getSmartDoubling() { @@ -41,13 +41,35 @@ public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolde } // 触发一次刷新,让网络及时拿到最新状态(也会触发 ICraftingProvider.requestUpdate(mainNode)) ((AdvPatternProviderLogic) (Object) this).updatePatterns(); - } catch (Throwable ignored) { + } catch (Throwable ignored) {} + } + + @Override + public int eap$getProviderSmartDoublingLimit() { + return this.eap$providerScalingLimit; + } + + @Override + public void eap$setProviderSmartDoublingLimit(int limit) { + // 更新供应器级别上限并去抖保存 + var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); + this.eap$providerScalingLimit = Math.max(0, limit); + // 现在把防抖移到客户端屏幕端来处理,服务器端直接立即应用并保存 + for (IPatternDetails d : list) { + if (d instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern a) { + try { a.eap$setScalingLimit(this.eap$providerScalingLimit); } catch (Throwable ignored) {} + } } + try { + ((AdvPatternProviderLogic) (Object) this).updatePatterns(); + } catch (Throwable ignored) {} } @Inject(method = "writeToNBT", at = @At("TAIL")) private void eap$writeSmartDoublingToNbt(CompoundTag tag, CallbackInfo ci) { tag.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + // 保存供应器级别上限 + tag.putInt(EAP_PROVIDER_SCALING_LIMIT, this.eap$providerScalingLimit); } @Inject(method = "readFromNBT", at = @At("TAIL")) @@ -55,6 +77,9 @@ public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolde if (tag.contains(EAP_SMART_DOUBLING_KEY)) { this.eap$smartDoubling = tag.getBoolean(EAP_SMART_DOUBLING_KEY); } + if (tag.contains(EAP_PROVIDER_SCALING_LIMIT)) { + this.eap$providerScalingLimit = tag.getInt(EAP_PROVIDER_SCALING_LIMIT); + } } @Inject(method = "updatePatterns", at = @At("TAIL")) @@ -62,13 +87,14 @@ public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolde try { var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); boolean allow = this.eap$smartDoubling; + int limit = this.eap$providerScalingLimit; for (IPatternDetails details : list) { if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) { aware.eap$setAllowScaling(allow); + aware.eap$setScalingLimit(limit); } } - } catch (Throwable ignored) { - } + } catch (Throwable ignored) {} } @Shadow @@ -77,6 +103,7 @@ public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolde @Inject(method = "exportSettings(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("TAIL")) private void onExportSettings(CompoundTag output, CallbackInfo ci) { output.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + output.putInt(EAP_PROVIDER_SCALING_LIMIT, this.eap$providerScalingLimit); } @Inject(method = "importSettings(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/entity/player/Player;)V", at = @At("TAIL")) @@ -86,5 +113,9 @@ public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolde // 持久化到 world this.saveChanges(); } + if (input.contains(EAP_PROVIDER_SCALING_LIMIT)) { + this.eap$providerScalingLimit = input.getInt(EAP_PROVIDER_SCALING_LIMIT); + this.saveChanges(); + } } } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java index a39e29f..4be69e0 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java @@ -25,7 +25,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements IPatternPro // 选择一个未占用的 GUI 同步 id(AE2 已用到 7),这里使用 21 以避冲突 @Unique - @GuiSync(22) + @GuiSync(20) public boolean eap$AdvancedBlocking = false; @Inject(method = "broadcastChanges", at = @At("HEAD")) 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 976e4e2..704e0e8 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 @@ -24,8 +24,11 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro protected AdvPatternProviderLogic logic; @Unique - @GuiSync(23) + @GuiSync(21) public boolean eap$SmartDoubling = false; + @Unique + @GuiSync(22) + public int eap$PerProviderScalingLimit = 0; // 0 = no limit @Inject(method = "broadcastChanges", at = @At("HEAD")) private void eap$syncSmartDoubling(CallbackInfo ci) { @@ -33,6 +36,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro var l = this.logic; if (l instanceof ISmartDoublingHolder holder) { this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + this.eap$PerProviderScalingLimit = holder.eap$getProviderSmartDoublingLimit(); } } } @@ -43,6 +47,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro var l = this.logic; if (l instanceof ISmartDoublingHolder holder) { this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + this.eap$PerProviderScalingLimit = holder.eap$getProviderSmartDoublingLimit(); } } catch (Throwable ignored) {} } @@ -53,6 +58,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro var l = this.logic; if (l instanceof ISmartDoublingHolder holder) { this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + this.eap$PerProviderScalingLimit = holder.eap$getProviderSmartDoublingLimit(); } } catch (Throwable ignored) {} } @@ -61,4 +67,9 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternPro public boolean 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/helpers/PatternProviderLogicDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java index e8ed143..c1ee2af 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java @@ -63,7 +63,6 @@ public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder { try { ((PatternProviderLogic) (Object) this).updatePatterns(); } catch (Throwable ignored) {} - } @Inject(method = "writeToNBT", at = @At("TAIL"))