feat: 制作中打开供应器跳转到对应样板所在的页数

This commit is contained in:
C-H716 2025-09-02 12:46:23 +08:00
parent 29b92e4ee1
commit 1ca8c8c48e
4 changed files with 92 additions and 9 deletions

View File

@ -21,6 +21,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
@ -49,8 +50,8 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
super(menu, playerInventory, title, style); super(menu, playerInventory, title, style);
} }
// 移除手动挪动 Slot 坐标交由 SlotGridLayout + 原生布局控制 // 移除手动挪动 Slot 坐标交由 SlotGridLayout + 原生布局控制
@Unique @Unique
@ -144,7 +145,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
ContainerExPatternProvider menu1 = this.getMenu(); ContainerExPatternProvider menu1 = this.getMenu();
// 尝试调用 setPage // 尝试调用 setPage
try { try {
java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class); Method setPageMethod = menu1.getClass().getMethod("setPage", int.class);
setPageMethod.invoke(menu1, newPage); setPageMethod.invoke(menu1, newPage);
} catch (Throwable ignored2) {} } catch (Throwable ignored2) {}
// 直接写入 page 字段确保生效 // 直接写入 page 字段确保生效

View File

@ -11,11 +11,12 @@ import appeng.menu.AEBaseMenu;
import appeng.menu.locator.MenuLocators; import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftingCPUMenu; import appeng.menu.me.crafting.CraftingCPUMenu;
import appeng.parts.AEBasePart; import appeng.parts.AEBasePart;
import com.extendedae_plus.content.PatternHighlightStore;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
import com.extendedae_plus.util.PatternProviderDataUtil;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import java.util.Collection; import java.util.Collection;
@ -95,18 +96,35 @@ public class CraftingMonitorOpenProviderC2SPacket {
// 直接打开供应器自身的 UI调用 Host 默认方法 // 直接打开供应器自身的 UI调用 Host 默认方法
try { try {
// 告知目标玩家客户端高亮该 AEKey避免全局服务端状态污染 // 告知目标玩家客户端高亮该 AEKey避免全局服务端状态污染
try { AEKey key = pattern.getOutputs()[0].what();
AEKey key = pattern.getOutputs()[0].what(); ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT);
} catch (Throwable t) {}
// 部件与方块实体分别选择定位器 // 部件与方块实体分别选择定位器并打开界面
if (host instanceof AEBasePart part) { if (host instanceof AEBasePart part) {
host.openMenu(player, MenuLocators.forPart(part)); host.openMenu(player, MenuLocators.forPart(part));
} else { } else {
host.openMenu(player, MenuLocators.forBlockEntity(pbe)); host.openMenu(player, MenuLocators.forBlockEntity(pbe));
} }
// 先在该 provider 中定位 pattern 的槽位索引以便计算页码
int foundSlot = -1;
var list = PatternProviderDataUtil.getAllPatternData(ppl);
for (var pd : list) {
if (pd != null && pd.getPatternDetails() != null
&& pd.getPatternDetails().getDefinition().equals(pattern.getDefinition())) {
foundSlot = pd.getSlotIndex();
break;
}
}
if (foundSlot >= 0) {
int pageId = foundSlot / 36;
if (pageId > 0) {
// 发送 S2C 包通知客户端切换到指定页客户端会写入 mixin 字段并重排槽位
ModNetwork.CHANNEL.sendTo(new SetProviderPageS2CPacket(pageId), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
}
}
context.setPacketHandled(true); context.setPacketHandled(true);
return; return;
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -66,6 +66,12 @@ public class ModNetwork {
.consumerNetworkThread(SetPatternHighlightS2CPacket::handle) .consumerNetworkThread(SetPatternHighlightS2CPacket::handle)
.add(); .add();
CHANNEL.messageBuilder(SetProviderPageS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT)
.encoder(SetProviderPageS2CPacket::encode)
.decoder(SetProviderPageS2CPacket::decode)
.consumerNetworkThread(SetProviderPageS2CPacket::handle)
.add();
CHANNEL.messageBuilder(ToggleAdvancedBlockingC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER) CHANNEL.messageBuilder(ToggleAdvancedBlockingC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER)
.encoder(ToggleAdvancedBlockingC2SPacket::encode) .encoder(ToggleAdvancedBlockingC2SPacket::encode)
.decoder(ToggleAdvancedBlockingC2SPacket::decode) .decoder(ToggleAdvancedBlockingC2SPacket::decode)

View File

@ -0,0 +1,58 @@
package com.extendedae_plus.network;
import appeng.menu.SlotSemantics;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.lang.reflect.Field;
import java.util.function.Supplier;
/**
* S2C: 指示客户端在已打开的样板供应器界面切换到指定页
*/
public class SetProviderPageS2CPacket {
private final int page;
public SetProviderPageS2CPacket(int page) {
this.page = page;
}
public static void encode(SetProviderPageS2CPacket msg, FriendlyByteBuf buf) {
buf.writeVarInt(msg.page);
}
public static SetProviderPageS2CPacket decode(FriendlyByteBuf buf) {
int p = buf.readVarInt();
return new SetProviderPageS2CPacket(p);
}
public static void handle(SetProviderPageS2CPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
var ctx = ctxSupplier.get();
ctx.enqueueWork(() -> {
try {
Screen screen = Minecraft.getInstance().screen;
if (screen instanceof GuiExPatternProvider guiExPatternProvider) {
Field currentPage = screen.getClass().getDeclaredField("eap$currentPage");
currentPage.setAccessible(true);
currentPage.setInt(guiExPatternProvider, msg.page);
guiExPatternProvider.repositionSlots(SlotSemantics.ENCODED_PATTERN);
guiExPatternProvider.repositionSlots(SlotSemantics.STORAGE);
Field hs = screen.getClass().getDeclaredField("hoveredSlot");
hs.setAccessible(true);
hs.set(screen, null);
}
} catch (Throwable ignored) {
}
}
);
ctx.setPacketHandled(true);
}
}