package thaumicenergistics.common.network; import net.minecraft.client.Minecraft; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; import thaumicenergistics.ThaumicEnergistics; import thaumicenergistics.common.container.ContainerEssentiaCellWorkbench; /** * 客户端→服务端 网络包:源质元件工作台分区操作。 * 操作类型见 ACTION_* 常量;aspectA/aspectB 仅在对应操作使用(其余传 EMPTY)。 */ public record CellWorkbenchC2SPacket( int containerId, int action, ResourceLocation aspectA, ResourceLocation aspectB ) implements CustomPacketPayload { public static final int ACTION_REQUEST = 0; public static final int ACTION_ADD = 1; public static final int ACTION_REMOVE = 2; public static final int ACTION_REPLACE = 3; public static final int ACTION_CLEAR = 4; public static final int ACTION_PARTITION_TO_CONTENTS = 5; private static final ResourceLocation EMPTY = ResourceLocation.withDefaultNamespace("empty"); public static final Type TYPE = new Type<>(ThaumicEnergistics.id("cell_workbench_c2s")); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( ByteBufCodecs.VAR_INT, CellWorkbenchC2SPacket::containerId, ByteBufCodecs.VAR_INT, CellWorkbenchC2SPacket::action, ResourceLocation.STREAM_CODEC, CellWorkbenchC2SPacket::aspectA, ResourceLocation.STREAM_CODEC, CellWorkbenchC2SPacket::aspectB, CellWorkbenchC2SPacket::new ); @Override public Type type() { return TYPE; } // ===== 客户端静态发送(从当前打开的工作台菜单自动取 containerId) ===== private static void send(int action, ResourceLocation a, ResourceLocation b) { var player = Minecraft.getInstance().player; if (player == null) return; PacketDistributor.sendToServer(new CellWorkbenchC2SPacket(player.containerMenu.containerId, action, a, b)); } public static void sendRequestPartitions() { send(ACTION_REQUEST, EMPTY, EMPTY); } public static void sendAddAspect(ResourceLocation aspect) { send(ACTION_ADD, aspect, EMPTY); } public static void sendRemoveAspect(ResourceLocation aspect) { send(ACTION_REMOVE, aspect, EMPTY); } public static void sendReplaceAspect(ResourceLocation from, ResourceLocation to) { send(ACTION_REPLACE, from, to); } public static void sendClear() { send(ACTION_CLEAR, EMPTY, EMPTY); } public static void sendPartitionToContents() { send(ACTION_PARTITION_TO_CONTENTS, EMPTY, EMPTY); } // ===== 服务端处理 ===== public void handleOnServer(IPayloadContext ctx) { ctx.enqueueWork(() -> { if (ctx.player().containerMenu.containerId == this.containerId && ctx.player().containerMenu instanceof ContainerEssentiaCellWorkbench menu) { boolean changed; switch (this.action) { case ACTION_REQUEST -> { if (ctx.player() instanceof net.minecraft.server.level.ServerPlayer sp) { CellWorkbenchSyncPacket.sendToClient(sp, menu.getPartitionAspects()); } return; } case ACTION_ADD -> changed = menu.addAspectToPartition(this.aspectA); case ACTION_REMOVE -> changed = menu.removeAspectFromPartition(this.aspectA); case ACTION_REPLACE -> changed = menu.replaceAspectInPartition(this.aspectA, this.aspectB); case ACTION_CLEAR -> { menu.clearPartitioning(); changed = true; } case ACTION_PARTITION_TO_CONTENTS -> { menu.partitionToContents(); changed = true; } default -> changed = false; } if (changed) { if (ctx.player() instanceof net.minecraft.server.level.ServerPlayer sp) { CellWorkbenchSyncPacket.sendToClient(sp, menu.getPartitionAspects()); } } } }); } }