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

View File

@ -11,11 +11,12 @@ import appeng.menu.AEBaseMenu;
import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftingCPUMenu;
import appeng.parts.AEBasePart;
import com.extendedae_plus.content.PatternHighlightStore;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
import com.extendedae_plus.util.PatternProviderDataUtil;
import com.mojang.logging.LogUtils;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent;
import java.util.Collection;
@ -95,18 +96,35 @@ public class CraftingMonitorOpenProviderC2SPacket {
// 直接打开供应器自身的 UI调用 Host 默认方法
try {
// 告知目标玩家客户端高亮该 AEKey避免全局服务端状态污染
try {
AEKey key = pattern.getOutputs()[0].what();
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT);
} catch (Throwable t) {}
AEKey key = pattern.getOutputs()[0].what();
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
// 部件与方块实体分别选择定位器
// 部件与方块实体分别选择定位器并打开界面
if (host instanceof AEBasePart part) {
host.openMenu(player, MenuLocators.forPart(part));
} else {
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);
return;
} catch (Throwable t) {

View File

@ -66,6 +66,12 @@ public class ModNetwork {
.consumerNetworkThread(SetPatternHighlightS2CPacket::handle)
.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)
.encoder(ToggleAdvancedBlockingC2SPacket::encode)
.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);
}
}