调整AEBaseScreenMixin中的部分内容及部分类的名字;扩展样板供应器界面代码调整

This commit is contained in:
C-H716 2025-10-29 01:24:20 +08:00
parent f068f00e7d
commit de9cb29b6b
9 changed files with 89 additions and 188 deletions

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.api;
/**
* {@code GuiExPatternProviderMixin} 实现用于从通用的 Screen Mixin 中更新按钮布局
*/
public interface IExPatternButtonsAccessor {
public interface IExPatternButton {
/**
* 在每帧调用以维护扩展样板供应器右侧按钮的可见性重注册窗口尺寸变化与定位
*/

View File

@ -3,6 +3,8 @@ package com.extendedae_plus.api;
/**
* GuiExPatternProviderMixin 实现用于在客户端侧提供当前页号避免反射读取 AE2 内部字段失败
*/
public interface IExPatternPageAccessor {
public interface IExPatternPage {
int eap$getCurrentPage();
int eap$getMaxPageLocal();
}

View File

@ -11,9 +11,8 @@ import appeng.client.gui.me.crafting.CraftingCPUScreen;
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 appeng.menu.slot.AppEngSlot;
import com.extendedae_plus.api.IExPatternPageAccessor;
import com.extendedae_plus.api.IExPatternPage;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor;
@ -26,6 +25,7 @@ import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.Rect2i;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.contents.TranslatableContents;
@ -40,63 +40,45 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AEBaseScreen.class)
public abstract class AEBaseScreenMixin {
/**
* AEBaseScreen mouseClicked 入口拦截 CraftingCPUScreen Shift+左键
* 读取鼠标下的 AEKey 并发送 CraftingMonitorJumpC2SPacket
* AEBaseScreen mouseClicked 入口拦截 CraftingCPUScreen Shift+点击操作
* 左键发送 CraftingMonitorJumpC2SPacket跳转至样板所在界面
* 右键发送 CraftingMonitorOpenProviderC2SPacket打开样板供应器UI
*/
@Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true)
private void eap$craftingCpuShiftLeftClick(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
private void eap$craftingCpuShiftClick(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
// 仅处理 CraftingCPUScreen 实例
Object self = this;
if (!(self instanceof CraftingCPUScreen<?> screen)) {
return;
}
// 仅在 Shift + 左键 时触发
if (button != 0 || !net.minecraft.client.gui.screens.Screen.hasShiftDown()) {
return;
}
try {
StackWithBounds hovered = screen.getStackUnderMouse(mouseX, mouseY);
if (hovered == null || hovered.stack() == null) {
return;
}
AEKey key = hovered.stack().what();
if (key == null) {
return;
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorJumpC2SPacket(key));
cir.setReturnValue(true);
} catch (Throwable ignored) {}
}
/**
* AEBaseScreen mouseClicked 入口拦截 CraftingCPUScreen Shift+右键
* 读取鼠标下的 AEKey 并发送 CraftingMonitorOpenProviderC2SPacket打开样板供应器UI
*/
@Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true)
private void eap$craftingCpuShiftRightClick(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
// 仅处理 CraftingCPUScreen 实例
Object self = this;
if (!(self instanceof CraftingCPUScreen<?> screen)) {
return;
}
// 仅在 Shift + 右键 时触发
if (button != 1 || !net.minecraft.client.gui.screens.Screen.hasShiftDown()) {
// 仅在按下 Shift 且为左右键时触发
if (!Screen.hasShiftDown() || (button != 0 && button != 1)) {
return;
}
try {
StackWithBounds hovered = screen.getStackUnderMouse(mouseX, mouseY);
if (hovered == null || hovered.stack() == null) {
return;
}
AEKey key = hovered.stack().what();
if (key == null) {
return;
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorOpenProviderC2SPacket(key));
// 左键发送跳转包右键发送打开供应器包
if (button == 0) {
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorJumpC2SPacket(key));
} else {
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorOpenProviderC2SPacket(key));
}
cir.setReturnValue(true);
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
}
/**
@ -138,11 +120,14 @@ public abstract class AEBaseScreenMixin {
if (key != null && ClientPatternHighlightStore.hasHighlight(key)) {
try {
GuiUtil.drawSlotRainbowHighlight(guiGraphics, s.x, s.y);
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
}
}
} catch (Throwable ignore) {}
} catch (Throwable ignore) {}
} catch (Throwable ignore) {
}
} catch (Throwable ignore) {
}
}
// AEBaseScreen.drawText 完成某个文本绘制后若该文本为样板标签则紧接着绘制页码
@ -152,121 +137,64 @@ public abstract class AEBaseScreenMixin {
@Nullable TextOverride override,
CallbackInfo ci) {
Object self = this;
if (!(self instanceof GuiExPatternProvider)) {
if (!(self instanceof GuiExPatternProvider)) return;
// 判断是否是样板标题
Component content = text.getText();
if (!"gui.ae2.Patterns".equals(content.getContents() instanceof TranslatableContents tc ? tc.getKey() : null)) {
return;
}
try {
// 解析最终用于显示的标签内容
Component content = text.getText();
if (override != null && override.getContent() != null) {
content = override.getContent().copy().withStyle(content.getStyle());
}
// 计算样板文本起点与宽度按对齐方式与缩放修正 x/y
int imageWidth = ((AbstractContainerScreenAccessor<?>) this).eap$getImageWidth();
int imageHeight = ((AbstractContainerScreenAccessor<?>) this).eap$getImageHeight();
Rect2i bounds = new Rect2i(0, 0, imageWidth, imageHeight);
Point pos = text.getPosition().resolve(bounds);
float scale = text.getScale();
Font font = ((ScreenAccessor) this).eap$getFont();
// 只关心第一行标题类文本无换行或 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 IExPatternPageAccessor accessor) {
if (self instanceof IExPatternPage accessor) {
cur = Math.max(0, accessor.eap$getCurrentPage()) + 1;
}
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) {
max = Math.max(max, accessor.eap$getMaxPageLocal());
}
String pageText = "" + cur + "" + "/" + max + "";
// ---- 构造翻译文本 ----
Component pageText = Component.translatable("gui.extendedae.pattern_page", cur, max);
ScreenStyle style = ((AEBaseScreenAccessor<?>) this).eap$getStyle();
// ---- 计算绘制坐标 ----
AbstractContainerScreenAccessor<?> screen = (AbstractContainerScreenAccessor<?>) this;
int imageWidth = screen.eap$getImageWidth();
int imageHeight = screen.eap$getImageHeight();
Point pos = text.getPosition().resolve(
new Rect2i(0, 0, imageWidth, imageHeight)
);
Font font = ((ScreenAccessor) this).eap$getFont();
float scale = text.getScale();
int lineWidth = font.width(content.getVisualOrderText());
int x = pos.getX() + lineWidth + 4; // 右侧偏移4像素
int y = pos.getY();
// ---- 绘制 ----
int color = 0xFFFFFFFF;
ScreenStyle style = ((AEBaseScreenAccessor<?>) this).eap$getStyle();
if (style != null) {
try {
color = style.getColor(PaletteColor.DEFAULT_TEXT_COLOR).toARGB();
} 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();
color = style.getColor(PaletteColor.DEFAULT_TEXT_COLOR).toARGB();
}
guiGraphics.pose().pushPose();
guiGraphics.pose().translate(x, y, 1);
if (scale != 1.0f) guiGraphics.pose().scale(scale, scale, 1);
guiGraphics.drawString(font, pageText, 0, 0, color, false);
guiGraphics.pose().popPose();
} catch (Throwable ignored) {}
}
@Shadow(remap = false)
protected void setTextContent(String id, Component content) {};
protected void setTextContent(String id, Component content) {}
@Inject(method = "updateBeforeRender", at = @At("RETURN"), remap = false)
private void onUpdateBeforeRender(CallbackInfo ci) {
try {
AEBaseScreen<?> self = (AEBaseScreen<?>) (Object) this;
if (self instanceof PatternProviderScreen screen){
if (self instanceof PatternProviderScreen screen) {
Component t = screen.getTitle();
if (t != null && !t.getString().isEmpty()) {
this.setTextContent(AEBaseScreen.TEXT_ID_DIALOG_TITLE, t);

View File

@ -6,7 +6,7 @@ import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.SettingToggleButton;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IExPatternButton;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.init.ModNetwork;
@ -204,7 +204,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
private void eap$updateExGuiLayout() {
if ((Object) this instanceof GuiExPatternProvider) {
try {
((IExPatternButtonsAccessor) this).eap$updateButtonsLayout();
((IExPatternButton) this).eap$updateButtonsLayout();
} catch (Throwable t) {
EAP$LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString());
}

View File

@ -2,52 +2,31 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.Point;
import appeng.client.gui.layout.SlotGridLayout;
import com.extendedae_plus.api.IExPatternPageAccessor;
import com.extendedae_plus.api.IExPatternPage;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import net.minecraft.client.Minecraft;
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.CallbackInfoReturnable;
import java.lang.reflect.Field;
@Mixin(SlotGridLayout.class)
public abstract class SlotGridLayoutMixin {
@Unique
private static final int SLOTS_PER_PAGE = 36;
@Inject(method = "getRowBreakPosition", at = @At("HEAD"), cancellable = true, remap = false)
private static void onGetRowBreakPosition(int x, int y, int semanticIdx, int cols, CallbackInfoReturnable<Point> cir) {
// 仅在 9 列布局 当前屏幕为 扩展样板供应器 时处理
if (cols != 9) {
return;
}
// 仅在 9 列布局 当前屏幕为 扩展样板供应器时处理
if (cols != 9) return;
var screen = Minecraft.getInstance().screen;
if (!(screen instanceof com.glodblock.github.extendedae.client.gui.GuiExPatternProvider)) {
return;
}
if (!(screen instanceof GuiExPatternProvider gui)) return;
// 读取实际当前页码优先从 GUI accessor其次反射容器失败则为 0
int currentPage = 0;
try {
if (screen instanceof IExPatternPageAccessor 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 currentPage = (gui instanceof IExPatternPage accessor) ?
accessor.eap$getCurrentPage() :
0;
// 该槽位属于第几页
int slotPage = semanticIdx / SLOTS_PER_PAGE;
int slotPage = semanticIdx / 36;
if (slotPage != currentPage) {
// 非当前页将其移出视野避免渲染与鼠标命中
cir.setReturnValue(new Point(-10000, -10000));
@ -56,7 +35,7 @@ public abstract class SlotGridLayoutMixin {
}
// 当前页中的位置0..35
int slotInPage = semanticIdx % SLOTS_PER_PAGE;
int slotInPage = semanticIdx % 36;
int row = slotInPage / 9; // 0-3
int col = slotInPage % 9; // 0-8
@ -67,17 +46,5 @@ public abstract class SlotGridLayoutMixin {
cir.setReturnValue(new Point(targetX, targetY));
cir.cancel();
}
@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;
}
}

View File

@ -5,8 +5,8 @@ import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.menu.SlotSemantics;
import com.extendedae_plus.ae.client.gui.NewIcon;
import com.extendedae_plus.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IExPatternPageAccessor;
import com.extendedae_plus.api.IExPatternButton;
import com.extendedae_plus.api.IExPatternPage;
import com.extendedae_plus.config.ModConfig;
import com.glodblock.github.extendedae.client.button.ActionEPPButton;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
@ -24,10 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static com.extendedae_plus.util.Logger.EAP$LOGGER;
@Mixin(GuiExPatternProvider.class)
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements IExPatternButtonsAccessor, IExPatternPageAccessor {
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements IExPatternButton, IExPatternPage {
@Unique
ScreenStyle eap$screenStyle;
@ -239,6 +237,11 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
return getCurrentPage();
}
@Override
public int eap$getMaxPageLocal() {
return this.eap$maxPageLocal;
}
// 页码文本绘制移交给 AEBaseScreenMixin.renderLabels 尾部执行
// 注意不再注入 Screen#init避免混入在某些映射情况下失败导致 TransformerError

View File

@ -37,7 +37,6 @@ import static guideme.compiler.tags.MdxAttrs.getRequiredItemAndId;
public abstract class ItemLinkCompilerMixin {
@Inject(method = "compile", at = @At("HEAD"), cancellable = true)
private void onCompile(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el, CallbackInfo ci) {
System.out.println("加载guideme.compiler.tags.ItemLinkCompilerMixin.onCompile");
var itemAndId = this.getRequiredItemStackAndId(compiler, parent, el);
if (itemAndId == null) {
ci.cancel();

View File

@ -8,6 +8,7 @@
"gui.extendedae_plus.global.toggle_smart_doubling": "Toggle Smart Doubling",
"gui.extendedae_plus.global.all_on": "All On",
"gui.extendedae_plus.global.all_off": "All Off",
"gui.extendedae.pattern_page": "Page %s/%s",
"itemGroup.extendedae_plus.main": "ExtendedAE Plus",
"item.extendedae_plus.wireless_transceiver": "Wireless Transceiver",

View File

@ -8,6 +8,7 @@
"gui.extendedae_plus.global.toggle_smart_doubling": "切换智能翻倍",
"gui.extendedae_plus.global.all_on": "全部开启",
"gui.extendedae_plus.global.all_off": "全部关闭",
"gui.extendedae.pattern_page": "第%s页/%s页",
"itemGroup.extendedae_plus.main": "扩展AE Plus",
"item.extendedae_plus.wireless_transceiver": "无线收发器",