From fccf7b88a1fe44c7b1e5c1958fb0c349d272fa77 Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Fri, 22 Aug 2025 10:58:32 +0800 Subject: [PATCH 1/5] 1 --- build.gradle | 9 +++++++++ .../extendedae_plus/util/ExtendedAELogger.java | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/main/java/com/extendedae_plus/util/ExtendedAELogger.java diff --git a/build.gradle b/build.gradle index 20fc150..d6e3dd3 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,15 @@ loom { forge { mixinConfig 'extendedae_plus.mixins.json' } + + runs { + client1 { + client() + name "Client 1" + runDir "run/client1" + programArgs "--username", "Player1" + } + } } repositories { diff --git a/src/main/java/com/extendedae_plus/util/ExtendedAELogger.java b/src/main/java/com/extendedae_plus/util/ExtendedAELogger.java new file mode 100644 index 0000000..e09228f --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/ExtendedAELogger.java @@ -0,0 +1,18 @@ +package com.extendedae_plus.util; + +import com.extendedae_plus.ExtendedAEPlus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 统一日志工具类。 + * 在需要的类中可使用: + * import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; + */ +public final class ExtendedAELogger { + public static final Logger LOGGER = LoggerFactory.getLogger(ExtendedAEPlus.MODID); + + private ExtendedAELogger() { + // no instance + } +} From 6362c79a666bf6d04f919dc67892487d5b44a8b5 Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Fri, 22 Aug 2025 12:00:06 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E9=98=BB=E6=8C=A1=E5=A4=9A=E4=BA=BA=E6=B8=B8=E6=88=8F=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=8A=B6=E6=80=81=E5=90=8C=E6=AD=A5=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../ae2/PatternProviderMenuAdvancedMixin.java | 12 +- .../mixin/ae2/PatternProviderScreenMixin.java | 126 ++++++------------ .../ToggleAdvancedBlockingC2SPacket.java | 13 +- 4 files changed, 48 insertions(+), 105 deletions(-) diff --git a/gradle.properties b/gradle.properties index 25a6e90..36d7385 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.3.2-beta +mod_version = 1.3.2-fix1 maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderMenuAdvancedMixin.java index 2809ac4..719fcaa 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderMenuAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderMenuAdvancedMixin.java @@ -2,6 +2,7 @@ package com.extendedae_plus.mixin.ae2; import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogicHost; +import appeng.menu.AEBaseMenu; import appeng.menu.guisync.GuiSync; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.AdvancedBlockingHolder; @@ -20,9 +21,6 @@ import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; @Mixin(PatternProviderMenu.class) public abstract class PatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { - @Shadow - protected abstract boolean isServerSide(); - @Shadow protected PatternProviderLogic logic; @@ -33,18 +31,16 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide @Inject(method = "broadcastChanges", at = @At("HEAD")) private void eap$syncAdvancedBlocking(CallbackInfo ci) { - if (this.isServerSide()) { + // 避免@Shadow父类方法,改用公共API:AEBaseMenu#isClientSide() + if (!((AEBaseMenu) (Object) this).isClientSide()) { var l = this.logic; if (l instanceof AdvancedBlockingHolder holder) { this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); + LOGGER.debug("[EAP] Menu broadcastChanges HEAD: eap$AdvancedBlocking={}", this.eap$AdvancedBlocking); } } } - @Inject(method = "broadcastChanges", at = @At("TAIL")) - private void eap$syncAdvancedBlockingTail(CallbackInfo ci) { - } - // 构造器尾注入(public ctor) @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL")) private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java index 99db84b..4d3fc71 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java @@ -4,12 +4,11 @@ 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.ToggleButton; +import appeng.client.gui.widgets.SettingToggleButton; +import appeng.api.config.YesNo; +import appeng.api.config.Settings; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; -import com.extendedae_plus.client.ClientAdvancedBlockingState; -import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; -import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import com.extendedae_plus.network.ModNetwork; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; import net.minecraft.network.chat.Component; @@ -21,122 +20,79 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; + /** - * 为 AE2 原版样板供应器界面添加“高级阻挡模式”按钮(仅客户端UI反馈)。 + * 为 AE2 原版样板供应器界面添加“高级阻挡模式”按钮。 * - 位于左侧工具栏 - * - 点击后切换图标(YES/NO)并切换 tooltip 提示 - * - 当前不做任何网络/服务端逻辑 + * - 点击仅发送 C2S 切换请求;状态由 AE2 @GuiSync 回传决定 */ @Mixin(PatternProviderScreen.class) public abstract class PatternProviderScreenMixin extends AEBaseScreen { @Unique - private ToggleButton eap$AdvancedBlockingToggle; + private SettingToggleButton eap$AdvancedBlockingToggle; @Unique private boolean eap$AdvancedBlockingEnabled = false; - @Unique - private String eap$ProviderKey = null; - public PatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) { super(menu, playerInventory, title, style); } @Inject(method = "", at = @At("RETURN")) private void eap$initAdvancedBlocking(C menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { - // 计算供应器唯一键:维度ID + 方块坐标 + // 使用 @GuiSync 初始化 try { - var logic = ((PatternProviderMenuAdvancedAccessor) menu).eap$logic(); - var host = ((PatternProviderLogicAccessor) logic).eap$host(); - var be = host.getBlockEntity(); - var level = be.getLevel(); - String dimId = level.dimension().location().toString(); - long posLong = be.getBlockPos().asLong(); - this.eap$ProviderKey = ClientAdvancedBlockingState.key(dimId, posLong); + if (menu instanceof PatternProviderMenuAdvancedSync sync) { + this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); + } } catch (Throwable t) { LOGGER.error("Error initializing advanced sync", t); } - // 优先使用该供应器最近一次 S2C 状态;否则回退读取 @GuiSync 初始化 - if (this.eap$ProviderKey != null && ClientAdvancedBlockingState.has(this.eap$ProviderKey)) { - this.eap$AdvancedBlockingEnabled = ClientAdvancedBlockingState.get(this.eap$ProviderKey); - } else if (menu instanceof PatternProviderMenuAdvancedSync sync) { - this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); - } - // 使用 ToggleButton 以便在 YES/NO 图标与提示之间动态切换 - this.eap$AdvancedBlockingToggle = new ToggleButton( - Icon.BLOCKING_MODE_YES, - Icon.BLOCKING_MODE_NO, - // 提示文本:名称与说明 - Component.literal("高级阻挡模式"), - Component.literal("高级阻挡模式:当开启时,执行更严格的阻挡判定"), - (state) -> { - // 客户端立即反馈:切换图标/提示 - this.eap$AdvancedBlockingEnabled = state; - this.eap$AdvancedBlockingToggle.setState(state); - // 发送 C2S 切换请求 + // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” + this.eap$AdvancedBlockingToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 + LOGGER.debug("[EAP] Click advanced blocking toggle: send C2S"); ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); - // 可根据状态调整提示文本(演示性:开启/关闭不同第二行) - if (state) { - this.eap$AdvancedBlockingToggle.setTooltipOn(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal("高级阻挡模式:已开启"))); - this.eap$AdvancedBlockingToggle.setTooltipOff(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal("高级阻挡模式:已开启"))); - } else { - this.eap$AdvancedBlockingToggle.setTooltipOn(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal("高级阻挡模式:已关闭"))); - this.eap$AdvancedBlockingToggle.setTooltipOff(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal("高级阻挡模式:已关闭"))); - } } - ); - this.eap$AdvancedBlockingToggle.setState(this.eap$AdvancedBlockingEnabled); - // 初始 tooltip - this.eap$AdvancedBlockingToggle.setTooltipOn(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal(this.eap$AdvancedBlockingEnabled ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭") - )); - this.eap$AdvancedBlockingToggle.setTooltipOff(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal(this.eap$AdvancedBlockingEnabled ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭") - )); + ) { + @Override + public java.util.List getTooltipMessage() { + boolean enabled = eap$AdvancedBlockingEnabled; + var title = net.minecraft.network.chat.Component.literal("智能阻挡"); + var line = enabled + ? net.minecraft.network.chat.Component.literal("已启用:YES") + : net.minecraft.network.chat.Component.literal("已禁用:NO"); + return java.util.List.of(title, line); + } + }; + // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 + LOGGER.debug("[EAP] Screen init: initial synced={} -> set button", this.eap$AdvancedBlockingEnabled); + this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); } - // 每帧刷新:从菜单同步布尔值,保持按钮状态一致 - @Inject(method = "updateBeforeRender", at = @At("TAIL"), remap = false) + // 每帧刷新:仅从菜单(@GuiSync)同步布尔值,保持按钮状态一致 + @Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false) private void eap$updateAdvancedBlocking(CallbackInfo ci) { - // 打印一条轻量 tick 日志以确认该方法被调用(频繁输出可在验证后移除) - // System.out.println("[EPP][CLIENT] updateBeforeRender tick, local=" + this.eppAdvancedBlockingEnabled); - if (this.eap$AdvancedBlockingToggle == null) return; boolean desired = this.eap$AdvancedBlockingEnabled; - // 优先使用该供应器最近一次 S2C 值 - if (this.eap$ProviderKey != null && ClientAdvancedBlockingState.has(this.eap$ProviderKey)) { - desired = ClientAdvancedBlockingState.get(this.eap$ProviderKey); - } else if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { + if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { desired = sync.eap$getAdvancedBlockingSynced(); } - if (desired != this.eap$AdvancedBlockingEnabled) { - this.eap$AdvancedBlockingEnabled = desired; - this.eap$AdvancedBlockingToggle.setState(desired); - // 同步 tooltip 二行提示 - this.eap$AdvancedBlockingToggle.setTooltipOn(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal(desired ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭") - )); - this.eap$AdvancedBlockingToggle.setTooltipOff(java.util.List.of( - Component.literal("高级阻挡模式"), - Component.literal(desired ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭") - )); + // 与AE2一致:每帧无条件对齐按钮状态至@GuiSync(使用YesNo以获得原版图标与提示) + LOGGER.debug("[EAP] updateBeforeRender tick: desired={}", desired); + if (this.eap$AdvancedBlockingEnabled != desired) { + LOGGER.debug("[EAP] updateBeforeRender: desired changed {} -> {}", this.eap$AdvancedBlockingEnabled, desired); } + this.eap$AdvancedBlockingEnabled = desired; + this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); } } diff --git a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java index 49ed237..74bfdea 100644 --- a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java @@ -2,11 +2,9 @@ package com.extendedae_plus.network; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.AdvancedBlockingHolder; -import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; @@ -22,7 +20,7 @@ public class ToggleAdvancedBlockingC2SPacket { public static ToggleAdvancedBlockingC2SPacket decode(FriendlyByteBuf buf) { return new ToggleAdvancedBlockingC2SPacket(); - } + } public static void handle(ToggleAdvancedBlockingC2SPacket msg, Supplier ctxSupplier) { var ctx = ctxSupplier.get(); @@ -38,15 +36,8 @@ public class ToggleAdvancedBlockingC2SPacket { boolean current = holder.eap$getAdvancedBlocking(); boolean next = !current; holder.eap$setAdvancedBlocking(next); - // 关键:保存持久化,触发 AE2 写入逻辑(writeToNBT),并由菜单 @GuiSync 同步回客户端 + // 保存并触发 AE2 的菜单 @GuiSync 广播到所有观看该菜单的玩家 logic.saveChanges(); - // 直接下发 S2C 强制同步(带供应器标识:维度+方块坐标) - var host = ((PatternProviderLogicAccessor) logic).eap$host(); - var be = host.getBlockEntity(); - var level = be.getLevel(); - String dimId = level.dimension().location().toString(); - long posLong = be.getBlockPos().asLong(); - ModNetwork.CHANNEL.sendTo(new AdvancedBlockingSyncS2CPacket(dimId, posLong, next), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); } }); ctx.setPacketHandled(true); From 20071e126ddd47aef08ba90808edfe82bfef9a9b Mon Sep 17 00:00:00 2001 From: GaLi <3096147684@qq.com> Date: Fri, 22 Aug 2025 13:21:01 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E4=BF=AE=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/ExPatternButtonsAccessor.java | 11 + .../api/ExPatternPageAccessor.java | 8 + .../mixin/ae2/PatternProviderScreenMixin.java | 11 + .../mixin/ae2/SlotGridLayoutMixin.java | 51 ++- .../extendedae/GuiExPatternProviderMixin.java | 414 +++++++++--------- 5 files changed, 273 insertions(+), 222 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/api/ExPatternButtonsAccessor.java create mode 100644 src/main/java/com/extendedae_plus/api/ExPatternPageAccessor.java diff --git a/src/main/java/com/extendedae_plus/api/ExPatternButtonsAccessor.java b/src/main/java/com/extendedae_plus/api/ExPatternButtonsAccessor.java new file mode 100644 index 0000000..d97f448 --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/ExPatternButtonsAccessor.java @@ -0,0 +1,11 @@ +package com.extendedae_plus.api; + +/** + * 由 {@code GuiExPatternProviderMixin} 实现,用于从通用的 Screen Mixin 中更新按钮布局。 + */ +public interface ExPatternButtonsAccessor { + /** + * 在每帧调用以维护扩展样板供应器右侧按钮的可见性、重注册(窗口尺寸变化)与定位。 + */ + void eap$updateButtonsLayout(); +} diff --git a/src/main/java/com/extendedae_plus/api/ExPatternPageAccessor.java b/src/main/java/com/extendedae_plus/api/ExPatternPageAccessor.java new file mode 100644 index 0000000..fca633f --- /dev/null +++ b/src/main/java/com/extendedae_plus/api/ExPatternPageAccessor.java @@ -0,0 +1,8 @@ +package com.extendedae_plus.api; + +/** + * 由 GuiExPatternProviderMixin 实现,用于在客户端侧提供当前页号,避免反射读取 AE2 内部字段失败。 + */ +public interface ExPatternPageAccessor { + int eap$getCurrentPage(); +} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java index 4d3fc71..ed04380 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/PatternProviderScreenMixin.java @@ -11,6 +11,8 @@ import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.network.ModNetwork; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; +import com.extendedae_plus.api.ExPatternButtonsAccessor; +import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import org.spongepowered.asm.mixin.Mixin; @@ -94,5 +96,14 @@ public abstract class PatternProviderScreenMixin } this.eap$AdvancedBlockingEnabled = desired; this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); + + // 如果当前屏幕是 ExtendedAE 的 GuiExPatternProvider,则委托布局更新到 accessor + if ((Object) this instanceof GuiExPatternProvider) { + try { + ((ExPatternButtonsAccessor) this).eap$updateButtonsLayout(); + } catch (Throwable t) { + LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString()); + } + } } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/SlotGridLayoutMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/SlotGridLayoutMixin.java index e4a9eff..e101c32 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/SlotGridLayoutMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/SlotGridLayoutMixin.java @@ -8,6 +8,7 @@ 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.CallbackInfoReturnable; +import java.lang.reflect.Field; @Mixin(SlotGridLayout.class) public abstract class SlotGridLayoutMixin { @@ -27,18 +28,54 @@ public abstract class SlotGridLayoutMixin { return; } - // 计算当前页码 - int currentPage = semanticIdx / SLOTS_PER_PAGE; - - // 计算在当前页中的位置 + // 读取实际当前页码:优先从 GUI accessor,其次反射容器,失败则为 0 + int currentPage = 0; + try { + if (screen instanceof com.extendedae_plus.api.ExPatternPageAccessor accessor) { + currentPage = accessor.eap$getCurrentPage(); + } else { + var menu = ((com.glodblock.github.extendedae.client.gui.GuiExPatternProvider) screen).getMenu(); + Field fieldPage = eap$findFieldRecursive(menu.getClass(), "page"); + if (fieldPage != null) { + fieldPage.setAccessible(true); + currentPage = (Integer) fieldPage.get(menu); + } + } + } catch (Throwable ignored) { + } + + // 该槽位属于第几页 + int slotPage = semanticIdx / SLOTS_PER_PAGE; + if (slotPage != currentPage) { + // 非当前页:将其移出视野,避免渲染与鼠标命中 + cir.setReturnValue(new Point(-10000, -10000)); + cir.cancel(); + return; + } + + // 当前页中的位置(0..35) int slotInPage = semanticIdx % SLOTS_PER_PAGE; int row = slotInPage / 9; // 0-3 int col = slotInPage % 9; // 0-8 - + // 计算目标位置(始终在前4行) int targetX = x + col * 18; int targetY = y + row * 18; - + cir.setReturnValue(new Point(targetX, targetY)); + cir.cancel(); } -} \ No newline at end of file + + @Unique + private static Field eap$findFieldRecursive(Class cls, String name) { + Class c = cls; + while (c != null && c != Object.class) { + try { + return c.getDeclaredField(name); + } catch (NoSuchFieldException ignored) {} + c = c.getSuperclass(); + } + return null; + } +} + \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java index 08c2960..882fe9e 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java @@ -7,12 +7,12 @@ import appeng.client.gui.style.ScreenStyle; import appeng.menu.SlotSemantics; import com.extendedae_plus.NewIcon; import com.glodblock.github.extendedae.client.button.ActionEPPButton; +import com.extendedae_plus.api.ExPatternButtonsAccessor; +import com.extendedae_plus.config.ModConfigs; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import com.glodblock.github.extendedae.container.ContainerExPatternProvider; import com.glodblock.github.extendedae.network.EPPNetworkHandler; import com.glodblock.github.glodium.network.packet.CGenericPacket; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; @@ -25,9 +25,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.lang.reflect.Field; import java.util.List; +import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; @Mixin(GuiExPatternProvider.class) -public abstract class GuiExPatternProviderMixin extends PatternProviderScreen { +public abstract class GuiExPatternProviderMixin extends PatternProviderScreen implements ExPatternButtonsAccessor, com.extendedae_plus.api.ExPatternPageAccessor { @Unique ScreenStyle eap$screenStyle; @@ -41,224 +42,68 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen SLOTS_PER_PAGE) { - Font fontRenderer = Minecraft.getInstance().font; - - // 获取当前页码 - int currentPage = getCurrentPage(); - int maxPage = getMaxPage(); - - // 获取ae通用界面样式 - int color = eap$screenStyle.getColor(PaletteColor.DEFAULT_TEXT_COLOR).toARGB(); - // 调整页码显示位置:在"样板"文字的右边 - guiGraphics.drawString(font, Component.literal("第 " + (currentPage + 1) + "/" + maxPage + " 页"), - leftPos + 8 + 50, topPos + 30, color, false); - } - } - - @Unique - public void updateBeforeRender() { - super.updateBeforeRender(); - try { - ContainerExPatternProvider menu1 = this.getMenu(); - - // 调用showPage方法 - java.lang.reflect.Method showPageMethod = menu1.getClass().getMethod("showPage"); - showPageMethod.invoke(menu1); - - // 获取当前页码和最大页码 - Field fieldPage = menu1.getClass().getDeclaredField("page"); - fieldPage.setAccessible(true); - Integer page = (Integer) fieldPage.get(menu1); - - Field fieldMaxPage = menu1.getClass().getDeclaredField("maxPage"); - fieldMaxPage.setAccessible(true); - Integer maxPage = (Integer) fieldMaxPage.get(menu1); - - // 更新按钮可见性 - 始终显示,支持循环翻页 - if (nextPage != null && prevPage != null) { - this.nextPage.setVisibility(true); - this.prevPage.setVisibility(true); - } - if (x2Button != null) { - this.x2Button.setVisibility(true); - } - if (divideBy2Button != null) { - this.divideBy2Button.setVisibility(true); - } - if (x10Button != null) { - this.x10Button.setVisibility(true); - } - if (divideBy10Button != null) { - this.divideBy10Button.setVisibility(true); - } - - // 调整槽位位置 - this.eap$adjustSlotPositions(page); - } catch (Exception e) { - // 忽略反射错误 - } - - // 如果屏幕尺寸发生变化(窗口/GUI缩放),重新注册按钮,避免被 Screen.init 清空 - if (this.width != eap$lastScreenWidth || this.height != eap$lastScreenHeight) { - eap$lastScreenWidth = this.width; - eap$lastScreenHeight = this.height; - try { - if (this.divideBy2Button != null) { - this.removeWidget(this.divideBy2Button); - this.addRenderableWidget(this.divideBy2Button); - } - if (this.x2Button != null) { - this.removeWidget(this.x2Button); - this.addRenderableWidget(this.x2Button); - } - if (this.divideBy5Button != null) { - this.removeWidget(this.divideBy5Button); - this.addRenderableWidget(this.divideBy5Button); - } - if (this.x5Button != null) { - this.removeWidget(this.x5Button); - this.addRenderableWidget(this.x5Button); - } - if (this.divideBy10Button != null) { - this.removeWidget(this.divideBy10Button); - this.addRenderableWidget(this.divideBy10Button); - } - if (this.x10Button != null) { - this.removeWidget(this.x10Button); - this.addRenderableWidget(this.x10Button); - } - } catch (Throwable ignored) {} - } - - // 每帧定位四个按钮到 GUI 右缘外侧一点(使用绝对屏幕坐标) - int bx = this.leftPos + this.imageWidth + 1; // 向右平移 1px 到面板外侧 - int by = this.topPos + 20; - int spacing = 22; - if (this.divideBy2Button != null) { - this.divideBy2Button.setVisibility(true); - this.divideBy2Button.setX(bx); - this.divideBy2Button.setY(by); - } - if (this.x2Button != null) { - this.x2Button.setVisibility(true); - this.x2Button.setX(bx); - this.x2Button.setY(by + spacing); - } - if (this.divideBy10Button != null) { - this.divideBy10Button.setVisibility(true); - this.divideBy10Button.setX(bx); - this.divideBy10Button.setY(by + spacing * 4); - } - if (this.x10Button != null) { - this.x10Button.setVisibility(true); - this.x10Button.setX(bx); - this.x10Button.setY(by + spacing * 5); - } - // 新增 /5 与 x5 的定位(位于 /2、x2 之后) - if (this.divideBy5Button != null) { - this.divideBy5Button.setVisibility(true); - this.divideBy5Button.setX(bx); - this.divideBy5Button.setY(by + spacing * 2); - } - if (this.x5Button != null) { - this.x5Button.setVisibility(true); - this.x5Button.setX(bx); - this.x5Button.setY(by + spacing * 3); - } - } - @Unique - private void eap$adjustSlotPositions(int currentPage) { - try { - List slots = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN); - int totalSlots = slots.size(); - - if (totalSlots <= SLOTS_PER_PAGE) { - return; // 不需要翻页 - } - - int slot_id = 0; - for (Slot s : slots) { - int page_id = slot_id / SLOTS_PER_PAGE; - - if (page_id == currentPage) { - // 当前页的槽位需要调整位置 - int slotInPage = slot_id % SLOTS_PER_PAGE; - int row = slotInPage / 9; // 0-3 - int col = slotInPage % 9; // 0-8 - - // 计算目标位置(始终在前4行) - int x = 8 + col * 18; - int y = 42 + row * 18; - - // 使用反射设置槽位位置,支持混淆环境 - Field xField = null; - Field yField = null; - - // 尝试不同的字段名(开发环境和生产环境可能不同) - String[] xFieldNames = {"x", "field_75262_c"}; - String[] yFieldNames = {"y", "field_75263_d"}; - - for (String fieldName : xFieldNames) { - try { - xField = Slot.class.getDeclaredField(fieldName); - xField.setAccessible(true); - break; - } catch (NoSuchFieldException ignored) {} - } - - for (String fieldName : yFieldNames) { - try { - yField = Slot.class.getDeclaredField(fieldName); - yField.setAccessible(true); - break; - } catch (NoSuchFieldException ignored) {} - } - - if (xField != null && yField != null) { - xField.set(s, x); - yField.set(s, y); - } - } - ++slot_id; - } - } catch (Exception e) { - // 忽略反射错误 - } - } + + // 移除手动挪动 Slot 坐标,交由 SlotGridLayout + 原生布局控制 @Unique private int getCurrentPage() { - try { - ContainerExPatternProvider menu1 = this.getMenu(); - Field fieldPage = menu1.getClass().getDeclaredField("page"); - fieldPage.setAccessible(true); - return (Integer) fieldPage.get(menu1); - } catch (Exception e) { - return 0; - } + // 优先使用本地 GUI 维护的页码 + return Math.max(0, eap$currentPage % Math.max(1, eap$maxPageLocal)); } @Unique private int getMaxPage() { + // 优先使用配置倍数 + try { + int cfg = ModConfigs.PAGE_MULTIPLIER.get(); + if (cfg > 1) return cfg; + } catch (Throwable ignored) {} try { ContainerExPatternProvider menu1 = this.getMenu(); - Field fieldMaxPage = menu1.getClass().getDeclaredField("maxPage"); - fieldMaxPage.setAccessible(true); - return (Integer) fieldMaxPage.get(menu1); - } catch (Exception e) { - return 1; + Field fieldMaxPage = eap$findFieldRecursive(menu1.getClass(), "maxPage"); + if (fieldMaxPage != null) { + fieldMaxPage.setAccessible(true); + Object v = fieldMaxPage.get(menu1); + if (v instanceof Integer i) return i; + } + } catch (Throwable ignored) {} + // 回退:用槽位总数计算 + try { + int totalSlots = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN).size(); + return Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE)); + } catch (Throwable ignored) {} + return 1; + } + + @Unique + private static Field eap$findFieldRecursive(Class cls, String name) { + Class c = cls; + while (c != null && c != Object.class) { + try { + return c.getDeclaredField(name); + } catch (NoSuchFieldException ignored) {} + c = c.getSuperclass(); + } + return null; + } + + @Unique + private static void eap$setIntFieldRecursive(Object obj, String name, int value) { + if (obj == null) return; + Field f = eap$findFieldRecursive(obj.getClass(), name); + if (f != null) { + try { f.setAccessible(true); f.set(obj, value); } catch (Throwable ignored) {} } } @@ -277,29 +122,75 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen SLOTS_PER_PAGE) { + int cfgPages = 1; + try { cfgPages = Math.max(1, ModConfigs.PAGE_MULTIPLIER.get()); } catch (Throwable ignored) {} + int calcPages = Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE)); + int desiredMaxPage = Math.max(cfgPages, calcPages); + LOGGER.info("[EAP] GuiExPatternProvider init: totalSlots={}, cfgPages={}, calcPages={}, desiredMaxPage={}", totalSlots, cfgPages, calcPages, desiredMaxPage); + // 更新本地最大页 + this.eap$maxPageLocal = Math.max(1, desiredMaxPage); + this.eap$currentPage = 0; + try { + Field fMax = eap$findFieldRecursive(menu.getClass(), "maxPage"); + if (fMax != null) { fMax.setAccessible(true); fMax.set(menu, desiredMaxPage); } + } catch (Throwable ignored) {} + + // 翻页按钮(当存在多页时显示;支持仅由配置决定的“空白页”) + if (desiredMaxPage > 1) { this.prevPage = new ActionEPPButton((b) -> { int currentPage = getCurrentPage(); - int maxPage = getMaxPage(); + int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage()); int newPage = (currentPage - 1 + maxPage) % maxPage; try { ContainerExPatternProvider menu1 = this.getMenu(); - java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); - setPageMethod.invoke(menu1, newPage); + // 尝试调用 setPage + try { + java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); + setPageMethod.invoke(menu1, newPage); + } catch (Throwable ignored2) {} + // 直接写入 page 字段,确保生效 + Field f = eap$findFieldRecursive(menu1.getClass(), "page"); + if (f != null) { + f.setAccessible(true); + f.set(menu1, newPage); + } } catch (Exception ignored) {} + // 同步到本地 GUI 页码 + this.eap$currentPage = newPage; + // 日志与强制重排(放在更新本地页码之后,确保布局读取到新页) + LOGGER.info("[EAP] PrevPage clicked: {} -> {} (max={})", currentPage, newPage, maxPage); + this.repositionSlots(SlotSemantics.ENCODED_PATTERN); + this.repositionSlots(SlotSemantics.STORAGE); + this.hoveredSlot = null; }, Icon.ARROW_LEFT); this.nextPage = new ActionEPPButton((b) -> { int currentPage = getCurrentPage(); - int maxPage = getMaxPage(); + int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage()); int newPage = (currentPage + 1) % maxPage; try { ContainerExPatternProvider menu1 = this.getMenu(); - java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); - setPageMethod.invoke(menu1, newPage); + // 尝试调用 setPage + try { + java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); + setPageMethod.invoke(menu1, newPage); + } catch (Throwable ignored2) {} + // 直接写入 page 字段,确保生效 + Field f = eap$findFieldRecursive(menu1.getClass(), "page"); + if (f != null) { + f.setAccessible(true); + f.set(menu1, newPage); + } } catch (Exception ignored) {} + // 同步到本地 GUI 页码 + this.eap$currentPage = newPage; + // 日志与强制重排(放在更新本地页码之后,确保布局读取到新页) + LOGGER.info("[EAP] NextPage clicked: {} -> {} (max={})", currentPage, newPage, maxPage); + this.repositionSlots(SlotSemantics.ENCODED_PATTERN); + this.repositionSlots(SlotSemantics.STORAGE); + this.hoveredSlot = null; }, Icon.ARROW_RIGHT); this.addToLeftToolbar(this.nextPage); @@ -346,8 +237,101 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen Date: Fri, 22 Aug 2025 13:41:06 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E4=BF=AE=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mixin/ae2/AEBaseScreenMixin.java | 102 ++++++++++++++++++ .../extendedae/GuiExPatternProviderMixin.java | 6 +- .../resources/extendedae_plus.mixins.json | 1 + 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java new file mode 100644 index 0000000..aca8dbb --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java @@ -0,0 +1,102 @@ +package com.extendedae_plus.mixin.ae2; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.PaletteColor; +import appeng.client.gui.style.ScreenStyle; +import com.extendedae_plus.api.ExPatternPageAccessor; +import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +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; + +@Mixin(AEBaseScreen.class) +public abstract class AEBaseScreenMixin { + + @Unique + private ScreenStyle eap$getStyle(Object self) { + try { + var f = self.getClass().getDeclaredField("style"); + f.setAccessible(true); + Object v = f.get(self); + if (v instanceof ScreenStyle s) return s; + } catch (Throwable ignored) {} + return null; + } + + @Unique + private static int eap$getIntField(Object self, String name, int def) { + Class c = self.getClass(); + while (c != null && c != Object.class) { + try { + var f = c.getDeclaredField(name); + f.setAccessible(true); + Object v = f.get(self); + if (v instanceof Integer i) return i; + } catch (Throwable ignored) {} + c = c.getSuperclass(); + } + return def; + } + + @Unique + private static Font eap$getFont(Object self) { + Class c = self.getClass(); + while (c != null && c != Object.class) { + try { + var f = c.getDeclaredField("font"); + f.setAccessible(true); + Object v = f.get(self); + if (v instanceof Font font) return font; + } catch (Throwable ignored) {} + c = c.getSuperclass(); + } + return net.minecraft.client.Minecraft.getInstance().font; + } + + // 在标签绘制后追加页码绘制,仅限扩展样板供应器界面 + @Inject(method = "renderLabels", at = @At("TAIL"), remap = false) + private void eap$renderPageIndicator(GuiGraphics guiGraphics, int x, int y, CallbackInfo ci) { + Object self = this; + if (!(self instanceof GuiExPatternProvider)) { + return; + } + int cur = 1; + int max = 1; + try { + if (self instanceof ExPatternPageAccessor accessor) { + cur = Math.max(0, accessor.eap$getCurrentPage()) + 1; + } + // 读取最大页(从 GUI 本地字段) + try { + var fMax = self.getClass().getDeclaredField("eap$maxPageLocal"); + fMax.setAccessible(true); + Object v = fMax.get(self); + if (v instanceof Integer i) { + max = Math.max(1, i); + } + } catch (Throwable ignored) {} + + ScreenStyle style = eap$getStyle(self); + Font font = eap$getFont(self); + int leftPos = eap$getIntField(self, "leftPos", 0); + int topPos = eap$getIntField(self, "topPos", 0); + int imageWidth = eap$getIntField(self, "imageWidth", 0); + + String text = cur + "/" + max; + int tx = leftPos + imageWidth - font.width(text) - 6; + int ty = topPos + 6; + int color = 0xFFFFFFFF; + if (style != null) { + try { + color = style.getColor(PaletteColor.MUTED_TEXT_COLOR).toARGB(); + } catch (Throwable ignored) {} + } + guiGraphics.drawString(font, text, tx, ty, color, false); + } catch (Throwable ignored) { + } + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java index 882fe9e..521fccb 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/GuiExPatternProviderMixin.java @@ -193,6 +193,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen Date: Fri, 22 Aug 2025 15:05:47 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E4=BF=AE=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mixin/ae2/AEBaseScreenMixin.java | 110 +++++++++++++++--- 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java index aca8dbb..9b11ab6 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/AEBaseScreenMixin.java @@ -1,12 +1,20 @@ package com.extendedae_plus.mixin.ae2; import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.TextOverride; +import appeng.client.Point; import appeng.client.gui.style.PaletteColor; import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.style.Text; +import appeng.client.gui.style.TextAlignment; import com.extendedae_plus.api.ExPatternPageAccessor; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -57,20 +65,84 @@ public abstract class AEBaseScreenMixin { return net.minecraft.client.Minecraft.getInstance().font; } - // 在标签绘制后追加页码绘制,仅限扩展样板供应器界面 - @Inject(method = "renderLabels", at = @At("TAIL"), remap = false) - private void eap$renderPageIndicator(GuiGraphics guiGraphics, int x, int y, CallbackInfo ci) { + // 在 AEBaseScreen.drawText 完成某个文本绘制后,若该文本为“样板”标签,则紧接着绘制页码。 + @Inject(method = "drawText", at = @At("TAIL"), remap = false) + private void eap$appendPageAfterPatternsLabel(GuiGraphics guiGraphics, + Text text, + @Nullable TextOverride override, + CallbackInfo ci) { Object self = this; if (!(self instanceof GuiExPatternProvider)) { return; } - int cur = 1; - int max = 1; + try { + // 解析最终用于显示的标签内容 + Component content = text.getText(); + if (override != null && override.getContent() != null) { + content = override.getContent().copy().withStyle(content.getStyle()); + } + + // 计算“样板”文本起点与宽度,按对齐方式与缩放修正 x/y + int imageWidth = eap$getIntField(self, "imageWidth", 0); + int imageHeight = eap$getIntField(self, "imageHeight", 0); + Rect2i bounds = new Rect2i(0, 0, imageWidth, imageHeight); + Point pos = text.getPosition().resolve(bounds); + + float scale = text.getScale(); + + Font font = eap$getFont(self); + // 只关心第一行(标题类文本无换行或 maxWidth<=0) + var contentLine = (text.getMaxWidth() <= 0) + ? content.getVisualOrderText() + : font.split(content, text.getMaxWidth()).get(0); + int lineWidth = font.width(contentLine); + + int x = pos.getX(); + int y = pos.getY(); + // 对齐修正 + var align = text.getAlign(); + if (align == TextAlignment.CENTER) { + int textPx = Math.round(lineWidth * scale); + x -= textPx / 2; + } else if (align == TextAlignment.RIGHT) { + int textPx = Math.round(lineWidth * scale); + x -= textPx; + } + + // 判断是否为“样板”组标题(多语言兼容且避免标题) + boolean isPatterns = false; + // 1) 基于翻译键 + var contents = content.getContents(); + if (contents instanceof TranslatableContents tc) { + String key = tc.getKey(); + if (key != null && key.endsWith(".patterns")) { + isPatterns = true; + } + } + // 2) 基于已知本地化键的字符串解析 + if (!isPatterns) { + String label = content.getString(); + if (label != null) { + if (label.equals(Component.translatable("gui.pattern_provider.patterns").getString())) isPatterns = true; + else if (label.equals(Component.translatable("gui.extendedae.patterns").getString())) isPatterns = true; + else if (label.equals(Component.translatable("gui.ae2.patterns").getString())) isPatterns = true; + } + } + // 3) 容错:中文“样板”且在标题下方(放宽到 y>=14)或文本正好等于“样板” + if (!isPatterns) { + String s = content.getString(); + if (s != null && ("样板".equals(s) || (s.contains("样板") && y >= 14))) { + isPatterns = true; + } + } + if (!isPatterns) return; + + int cur = 1; + int max = 1; if (self instanceof ExPatternPageAccessor accessor) { cur = Math.max(0, accessor.eap$getCurrentPage()) + 1; } - // 读取最大页(从 GUI 本地字段) try { var fMax = self.getClass().getDeclaredField("eap$maxPageLocal"); fMax.setAccessible(true); @@ -80,23 +152,25 @@ public abstract class AEBaseScreenMixin { } } catch (Throwable ignored) {} - ScreenStyle style = eap$getStyle(self); - Font font = eap$getFont(self); - int leftPos = eap$getIntField(self, "leftPos", 0); - int topPos = eap$getIntField(self, "topPos", 0); - int imageWidth = eap$getIntField(self, "imageWidth", 0); + String pageText = "第"+cur+"页" + "/" + max + "页"; - String text = cur + "/" + max; - int tx = leftPos + imageWidth - font.width(text) - 6; - int ty = topPos + 6; + ScreenStyle style = eap$getStyle(self); int color = 0xFFFFFFFF; if (style != null) { try { - color = style.getColor(PaletteColor.MUTED_TEXT_COLOR).toARGB(); + color = style.getColor(PaletteColor.DEFAULT_TEXT_COLOR).toARGB(); } catch (Throwable ignored) {} } - guiGraphics.drawString(font, text, tx, ty, color, false); - } catch (Throwable ignored) { - } + int padding = 4; + if (scale == 1.0f) { + guiGraphics.drawString(font, pageText, x + lineWidth + padding, y, color, false); + } else { + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(x, y, 1); + guiGraphics.pose().scale(scale, scale, 1); + guiGraphics.drawString(font, pageText, lineWidth + padding, 0, color, false); + guiGraphics.pose().popPose(); + } + } catch (Throwable ignored) {} } }