From d58e68abb2a194bb1e501e0f29869929b5edc41e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 27 May 2025 11:39:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(network):=20=E7=9B=91=E5=90=AC=E6=9B=B4?= =?UTF-8?q?=E5=A4=9A=E5=8F=91=E5=8C=85=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 5 + .../plugin/network/PacketConsumers.java | 135 +++++++++++++++++- .../bukkit/plugin/network/PacketIds.java | 10 ++ .../plugin/network/id/PacketIdFinder.java | 8 ++ .../plugin/network/id/PacketIds1_20.java | 25 ++++ .../plugin/network/id/PacketIds1_20_5.java | 26 ++++ .../craftengine/bukkit/util/Reflections.java | 36 +++-- gradle.properties | 2 +- 8 files changed, 237 insertions(+), 10 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 051d18e54..9c7b386bb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -175,6 +175,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); + registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY, this.packetIds.clientboundSetPlayerInventoryPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); } public static BukkitNetworkManager instance() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index e94c20751..b54d0434d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; +import com.google.common.collect.Lists; import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -1205,7 +1206,7 @@ public class PacketConsumers { } }; - private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception { + private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); @@ -2177,6 +2178,138 @@ public class PacketConsumers { } }; + public static final BiConsumer CONTAINER_SET_SLOT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int slot = buf.readShort(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetSlotPacket", e); + } + }; + + public static final BiConsumer SET_CURSOR_ITEM = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetCursorItemPacket", e); + } + }; + + public static final BiConsumer SET_EQUIPMENT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int entity = buf.readVarInt(); + List> slots = Lists.newArrayList(); + int _byte; + do { + _byte = buf.readByte(); + Object equipmentSlot = Reflections.instance$EquipmentSlot$values[_byte & 127]; + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, context); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); + } while ((_byte & -128) != 0); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(entity); + int i = slots.size(); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for(int j = 0; j < i; ++j) { + com.mojang.datafixers.util.Pair pair = slots.get(j); + Enum equipmentSlot = (Enum) pair.getFirst(); + boolean bl = j != i - 1; + int k = equipmentSlot.ordinal(); + buf.writeByte(bl ? k | -128 : k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e); + } + }; + + public static final BiConsumer SET_PLAYER_INVENTORY = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + int slot = buf.readVarInt(); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerInventoryPacket", e); + } + }; + + public static final BiConsumer SET_CREATIVE_MODE_SLOT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + short slotNum = buf.readShort(); + ItemStack itemStack; + if (VersionHelper.isOrAbove1_20_5()) { + itemStack = FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$readItem(friendlyBuf); + } else { + itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } + BukkitItemManager.instance().c2s(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeShort(slotNum); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + if (VersionHelper.isOrAbove1_20_5()) { + FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$writeItem(newFriendlyBuf, newItemStack); + } else { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + } + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); + } + }; + public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_2()) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 3433c5e56..6ee6e6d43 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -43,4 +43,14 @@ public interface PacketIds { int clientboundSetScorePacket(); int clientboundContainerSetContentPacket(); + + int clientboundContainerSetSlotPacket(); + + int clientboundSetCursorItemPacket(); + + int clientboundSetEquipmentPacket(); + + int clientboundSetPlayerInventoryPacket(); + + int serverboundSetCreativeModeSlotPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java index fc5594bfe..cff1f93b8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java @@ -43,4 +43,12 @@ public class PacketIdFinder { public static int clientboundByClazz(Class clazz) { return gamePacketIdsByClazz.get("clientbound").getOrDefault(clazz, -1); } + + public static int serverboundByName(String packetName) { + return gamePacketIdsByName.get("serverbound").getOrDefault(packetName, -1); + } + + public static int serverboundByClazz(Class clazz) { + return gamePacketIdsByClazz.get("serverbound").getOrDefault(clazz, -1); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index ea05910aa..04affb794 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -109,4 +109,29 @@ public class PacketIds1_20 implements PacketIds { public int clientboundContainerSetContentPacket() { return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundContainerSetContentPacket); } + + @Override + public int clientboundContainerSetSlotPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundContainerSetSlotPacket); + } + + @Override + public int clientboundSetCursorItemPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetCursorItemPacket); + } + + @Override + public int clientboundSetEquipmentPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetEquipmentPacket); + } + + @Override + public int clientboundSetPlayerInventoryPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetPlayerInventoryPacket); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PacketIdFinder.serverboundByClazz(Reflections.clazz$ServerboundSetCreativeModeSlotPacket); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index f5838edf2..0b3179372 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; +import net.momirealms.craftengine.bukkit.util.Reflections; public class PacketIds1_20_5 implements PacketIds { @@ -108,4 +109,29 @@ public class PacketIds1_20_5 implements PacketIds { public int clientboundContainerSetContentPacket() { return PacketIdFinder.clientboundByName("minecraft:container_set_content"); } + + @Override + public int clientboundContainerSetSlotPacket() { + return PacketIdFinder.clientboundByName("minecraft:container_set_slot"); + } + + @Override + public int clientboundSetCursorItemPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_cursor_item"); + } + + @Override + public int clientboundSetEquipmentPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_equipment"); + } + + @Override + public int clientboundSetPlayerInventoryPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index c7403b55a..d5360ca33 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -3111,6 +3111,7 @@ public class Reflections { ) ); + public static final Object[] instance$EquipmentSlot$values; public static final Object instance$EquipmentSlot$MAINHAND; public static final Object instance$EquipmentSlot$OFFHAND; public static final Object instance$EquipmentSlot$FEET; @@ -3121,14 +3122,14 @@ public class Reflections { static { try { - Object[] values = (Object[]) method$EquipmentSlot$values.invoke(null); - instance$EquipmentSlot$MAINHAND = values[0]; - instance$EquipmentSlot$OFFHAND = values[1]; - instance$EquipmentSlot$FEET = values[2]; - instance$EquipmentSlot$LEGS = values[3]; - instance$EquipmentSlot$CHEST = values[4]; - instance$EquipmentSlot$HEAD = values[5]; -// instance$EquipmentSlot$BODY = values[6]; + instance$EquipmentSlot$values = (Object[]) method$EquipmentSlot$values.invoke(null); + instance$EquipmentSlot$MAINHAND = instance$EquipmentSlot$values[0]; + instance$EquipmentSlot$OFFHAND = instance$EquipmentSlot$values[1]; + instance$EquipmentSlot$FEET = instance$EquipmentSlot$values[2]; + instance$EquipmentSlot$LEGS = instance$EquipmentSlot$values[3]; + instance$EquipmentSlot$CHEST = instance$EquipmentSlot$values[4]; + instance$EquipmentSlot$HEAD = instance$EquipmentSlot$values[5]; +// instance$EquipmentSlot$BODY = instance$EquipmentSlot$values[6]; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6828,4 +6829,23 @@ public class Reflections { "network.protocol.game.ClientboundContainerSetContentPacket" ) ); + + public static final Class clazz$ClientboundContainerSetSlotPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutSetSlot", + "network.protocol.game.ClientboundContainerSetSlotPacket" + ) + ); + + // 1.21.2+ + public static final Class clazz$ClientboundSetCursorItemPacket = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetCursorItemPacket") + ); + + // 1.21.2+ + public static final Class clazz$ClientboundSetPlayerInventoryPacket = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetPlayerInventoryPacket") + ); } diff --git a/gradle.properties b/gradle.properties index 261a2d7a2..3660116e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66 +nms_helper_version=0.67 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23