feat: 添加样板总成中处理样板数量显示。添加合成监控界面跳转支持,并高亮对应样板。调整依赖便于在gtlcore中测试

This commit is contained in:
C-H716 2025-09-05 18:18:06 +08:00
parent b0815924cc
commit dec1edbca3
8 changed files with 228 additions and 48 deletions

Binary file not shown.

View File

@ -40,6 +40,38 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AEBaseScreen.class)
public abstract class AEBaseScreenMixin {
@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;
}
@Unique
private ScreenStyle eap$getStyle(Object self) {
try {
@ -47,7 +79,8 @@ public abstract class AEBaseScreenMixin {
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof ScreenStyle s) return s;
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
return null;
}
@ -78,7 +111,8 @@ public abstract class AEBaseScreenMixin {
// Debug: 标记一次发送
try {
LogUtils.getLogger().info("EAP: Send CraftingMonitorJumpC2SPacket: {}", key);
} catch (Throwable ignored2) {}
} catch (Throwable ignored2) {
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorJumpC2SPacket(key));
cir.setReturnValue(true);
} catch (Throwable ignored) {
@ -112,43 +146,14 @@ public abstract class AEBaseScreenMixin {
// Debug: 标记一次发送打开供应器UI
try {
LogUtils.getLogger().info("EAP: Send CraftingMonitorOpenProviderC2SPacket: {}", key);
} catch (Throwable ignored2) {}
} catch (Throwable ignored2) {
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorOpenProviderC2SPacket(key));
cir.setReturnValue(true);
} catch (Throwable ignored) {
}
}
@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;
}
/**
* 重写renderSlot方法为所有可见的样板槽位添加数量显示
*/
@ -184,17 +189,14 @@ public abstract class AEBaseScreenMixin {
try {
var details = PatternDetailsHelper.decodePattern(itemStack, Minecraft.getInstance().level, false);
try {
if (details != null && details.getOutputs() != null && details.getOutputs().length > 0) {
AEKey key = details.getOutputs()[0].what();
if (key != null && ClientPatternHighlightStore.hasHighlight(key)) {
try {
GuiUtil.drawSlotRainbowHighlight(guiGraphics, s.x, s.y);
} catch (Throwable ignored) {}
}
if (details != null && details.getOutputs() != null && details.getOutputs().length > 0) {
AEKey key = details.getOutputs()[0].what();
if (key != null && ClientPatternHighlightStore.hasHighlight(key)) {
GuiUtil.drawSlotRainbowHighlight(guiGraphics, s.x, s.y);
}
} catch (Throwable ignore) {}
} catch (Throwable ignore) {}
}
} catch (Throwable ignore) {
}
}
// AEBaseScreen.drawText 完成某个文本绘制后若该文本为样板标签则紧接着绘制页码
@ -313,18 +315,22 @@ public abstract class AEBaseScreenMixin {
@Shadow
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);
}
}
} catch (Throwable ignored) {}
} catch (Throwable ignored) {
}
}
}

View File

@ -0,0 +1,54 @@
package com.extendedae_plus.mixin.gtceu;
import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.stacks.AEKey;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.extendedae_plus.util.GuiUtil;
import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEPatternViewSlotWidget;
import com.lowdragmc.lowdraglib.gui.widget.SlotWidget;
import com.lowdragmc.lowdraglib.utils.Position;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@OnlyIn(Dist.CLIENT)
@Mixin(value = AEPatternViewSlotWidget.class, remap = false)
public abstract class AEPatternViewSlotWidgetMixin {
/**
* AEPatternViewSlotWidget.drawBackgroundTexture(...) 尾部注入绘制数字逻辑
*/
@Inject(method = "drawBackgroundTexture", at = @At("TAIL"))
private void onDrawInBackgroundTail(GuiGraphics graphics, int mouseX, int mouseY, CallbackInfo ci) {
if (!AEPatternViewSlotWidget.class.isInstance(this)) return;
// this 强转为 SlotWidget目标类继承自 SlotWidget
SlotWidget self = (SlotWidget) (Object) this;
Slot handler = self.getHandler();
if (handler == null) return;
// 使用 getRealStack 来尊重 setItemHook 的渲染替换
ItemStack displayStack = self.getRealStack(handler.getItem());
if (displayStack == null || displayStack.isEmpty()) return;
ItemStack stack = handler.getItem();
Position pos = self.getPosition(); // 来自 Widget 的方法继承可用
try {
var details = PatternDetailsHelper.decodePattern(stack, Minecraft.getInstance().level, false);
if (details != null && details.getOutputs() != null && details.getOutputs().length > 0) {
AEKey key = details.getOutputs()[0].what();
if (key != null && ClientPatternHighlightStore.hasHighlight(key)) {
GuiUtil.drawSlotRainbowHighlight(graphics, pos.x + 1, pos.y + 1);
}
}
} catch (Throwable ignore) {
}
}
}

View File

@ -0,0 +1,19 @@
package com.extendedae_plus.mixin.gtceu;
import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.lowdragmc.lowdraglib.gui.modular.ModularUIContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = ModularUIContainer.class, remap = false)
public class ModularUIContainerCloseMixin {
@Inject(method = "removed", at = @At("HEAD"))
private void onRemoved(CallbackInfo ci) {
try {
ClientPatternHighlightStore.clearAll();
} catch (Throwable ignored) {}
}
}

View File

@ -0,0 +1,61 @@
package com.extendedae_plus.mixin.gtceu;
import com.extendedae_plus.util.GuiUtil;
import com.gregtechceu.gtceu.integration.ae2.gui.widget.slot.AEPatternViewSlotWidget;
import com.lowdragmc.lowdraglib.gui.util.DrawerHelper;
import com.lowdragmc.lowdraglib.gui.widget.SlotWidget;
import com.lowdragmc.lowdraglib.utils.Position;
import com.lowdragmc.lowdraglib.utils.Size;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@OnlyIn(Dist.CLIENT)
@Mixin(value = SlotWidget.class, remap = false)
public abstract class SlotWidgetMixin {
/**
* SlotWidget.drawInBackground(...) 尾部注入绘制数字逻辑
*/
@Inject(method = "drawInBackground(Lnet/minecraft/client/gui/GuiGraphics;IIF)V", at = @At("TAIL"))
private void onDrawInBackgroundTail(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks, CallbackInfo ci) {
if (!AEPatternViewSlotWidget.class.isInstance(this)) return;
// this 强转为 SlotWidget目标类继承自 SlotWidget
SlotWidget self = (SlotWidget) (Object) this;
Slot handler = self.getHandler();
if (handler == null) return;
// 使用 getRealStack 来尊重 setItemHook 的渲染替换
ItemStack displayStack = self.getRealStack(handler.getItem());
if (displayStack == null || displayStack.isEmpty()) return;
ItemStack stack = handler.getItem();
String patternOutputText = GuiUtil.getPatternOutputText(stack);
Position pos = self.getPosition(); // 来自 Widget 的方法继承可用
Size size = self.getSize(); // 同上
graphics.pose().pushPose();
graphics.pose().translate(0.0F, 0.0F, 300.0F);
RenderSystem.disableDepthTest();
DrawerHelper.drawStringFixedCorner(
graphics,
patternOutputText,
pos.x + size.width,
pos.y + size.height,
0xFFFFFFFF,
true,
0.75f);
RenderSystem.enableDepthTest();
graphics.pose().popPose();
}
}

View File

@ -15,6 +15,8 @@ import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
import com.extendedae_plus.util.PatternProviderDataUtil;
import com.glodblock.github.extendedae.util.FCClientUtil;
import com.glodblock.github.glodium.util.GlodUtil;
import com.gregtechceu.gtceu.api.gui.factory.MachineUIFactory;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.FriendlyByteBuf;
@ -133,6 +135,41 @@ public class CraftingMonitorOpenProviderC2SPacket {
return;
} catch (Exception ignored) {
}
} else if (provider instanceof com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine machine) {
// 处理 MEPatternBufferPartMachine打开其界面并高亮位置尽量反射获取槽位页码
try {
BlockPos pos = machine.getPos();
Level level = machine.getLevel();
if (pos == null || level == null) continue;
if (!level.isClientSide) { // 确保在服务器端执行
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
}
// 最后发送高亮包保证界面已打开
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
AEKey key = pattern.getOutputs()[0].what();
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
}
} catch (Exception ignored) {
}
} else if (provider instanceof org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEPatternBufferPartMachine machine) {
// 处理 MEPatternBufferPartMachine打开其界面并高亮位置尽量反射获取槽位页码
try {
BlockPos pos = machine.getPos();
Level level = machine.getLevel();
if (pos == null || level == null) continue;
if (!level.isClientSide) { // 确保在服务器端执行
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
}
// 最后发送高亮包保证界面已打开
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
AEKey key = pattern.getOutputs()[0].what();
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
}
} catch (Exception ignored) {
}
}
}
}

View File

@ -28,7 +28,7 @@ side = "BOTH"
[[dependencies.extendedae_plus]]
modId = "expatternprovider"
mandatory = true
versionRange = "[1.20-1.4.0-forge,)"
versionRange = "[1.20-1.1.12-forge,)"
ordering = "AFTER"
side = "BOTH"

View File

@ -23,6 +23,8 @@
"extendedae.client.HighlightButtonMixin",
"extendedae.client.gui.GuiExPatternProviderMixin",
"extendedae.client.gui.GuiExPatternTerminalMixin",
"gtceu.AEPatternViewSlotWidgetMixin",
"gtceu.SlotWidgetMixin",
"hooks.ModelBakeryMixin",
"jei.EncodePatternTransferHandlerMixin",
"jei.EncodingHelperMixin",
@ -56,7 +58,8 @@
"extendedae.common.TileExPatternProviderMixin",
"extendedae.container.ContainerExPatternProviderMixin",
"extendedae.container.ContainerExPatternTerminalMixin",
"extendedae.container.ContainerWirelessExPatternTerminalMixin"
"extendedae.container.ContainerWirelessExPatternTerminalMixin",
"gtceu.ModularUIContainerCloseMixin"
],
"injectors": {
"defaultRequire": 1