From 5e447505efa55cc466ba35383789b2f921eacd63 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 21:00:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=B6=E5=85=B7=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 2 +- .../plugin/network/PacketConsumers.java | 169 +++++++++++------- .../bukkit/plugin/network/PacketIds.java | 2 + .../plugin/network/id/PacketIds1_20.java | 5 + .../plugin/network/id/PacketIds1_20_5.java | 5 + 5 files changed, 122 insertions(+), 61 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 0e6a33c6e..f216d8443 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 @@ -147,7 +147,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.SET_CREATIVE_SLOT, NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket); registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket); - registerNMSPacketConsumer(PacketConsumers.INTERACT_ENTITY, NetworkReflections.clazz$ServerboundInteractPacket); registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); @@ -187,6 +186,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket()); + registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket()); } 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 f79e6800f..00fa3d042 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 @@ -50,10 +50,7 @@ import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.BlockHitResult; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.EntityHitResult; -import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; @@ -61,6 +58,7 @@ import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; @@ -1509,83 +1507,108 @@ public class PacketConsumers { } }; - public static final TriConsumer INTERACT_ENTITY = (user, event, packet) -> { + public static final BiConsumer INTERACT_ENTITY = (user, event) -> { try { - Player player = (Player) user.platformPlayer(); - if (player == null) return; - int entityId; - if (BukkitNetworkManager.hasModelEngine()) { - int fakeId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet); - entityId = CraftEngine.instance().compatibilityManager().interactionToBaseEntity(fakeId); - } else { - entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet); - } + FriendlyByteBuf buf = event.getBuffer(); + int entityId = BukkitNetworkManager.hasModelEngine() ? + CraftEngine.instance().compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : + buf.readVarInt(); BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; - Object action = NetworkReflections.field$ServerboundInteractPacket$action.get(packet); - Object actionType = NetworkReflections.method$ServerboundInteractPacket$Action$getType.invoke(action); - if (actionType == null) return; - Location location = furniture.baseEntity().getLocation(); + int actionType = buf.readVarInt(); BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; if (serverPlayer.isSpectatorMode()) return; - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$ATTACK) { + Player platformPlayer = serverPlayer.platformPlayer(); + Location location = furniture.baseEntity().getLocation(); + + Runnable mainThreadTask; + if (actionType == 1) { + // ATTACK + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { // todo 冒险模式破坏工具白名单 - if (serverPlayer.isAdventureMode()) return; - if (furniture.isValid()) { - if (!BukkitCraftEngine.instance().antiGrief().canBreak(player, location)) { - return; - } - FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(breakEvent)) { - return; - } + if (serverPlayer.isAdventureMode() || + !furniture.isValid() || + !BukkitCraftEngine.instance().antiGrief().canBreak(platformPlayer, location) + ) return; - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.LEFT_CLICK); - furniture.config().execute(context, EventTrigger.BREAK); + FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(breakEvent)) + return; - CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) + .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + return; } - } else if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) { - InteractionHand hand; - Location interactionPoint; - try { - Object interactionHand = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$hand.get(action); - hand = interactionHand == CoreReflections.instance$InteractionHand$MAIN_HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - Object vec3 = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$location.get(action); - double x = FastNMS.INSTANCE.field$Vec3$x(vec3); - double y = FastNMS.INSTANCE.field$Vec3$y(vec3); - double z = FastNMS.INSTANCE.field$Vec3$z(vec3); - interactionPoint = new Location(location.getWorld(), x, y, z); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to get interaction hand from interact packet", e); - } + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + }; + } else if (actionType == 2) { + // INTERACT_AT + float x = buf.readFloat(); + float y = buf.readFloat(); + float z = buf.readFloat(); + Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); + InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeFloat(x).writeFloat(y).writeFloat(z); + buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); if (EventUtils.fireAndCheckCancel(interactEvent)) { return; } + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); // execute functions PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.HAND, hand) .withParameter(DirectContextParameters.POSITION, furniture.position()) ); furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + if (cancellable.isCancelled()) { + return; + } - if (player.isSneaking()) { + // 必须从网络包层面处理,否则无法获取交互的具体实体 + if (serverPlayer.isSecondaryUseActive() && itemInHand != null) { // try placing another furniture above it AABB hitBox = furniture.aabbByEntityId(entityId); if (hitBox == null) return; - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - if (itemInHand == null) return; - Optional> optionalCustomitem = itemInHand.getCustomItem(); - Location eyeLocation = player.getEyeLocation(); + Optional> optionalCustomItem = itemInHand.getCustomItem(); + Location eyeLocation = platformPlayer.getEyeLocation(); Vector direction = eyeLocation.getDirection(); Location endLocation = eyeLocation.clone(); endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); @@ -1594,8 +1617,8 @@ public class PacketConsumers { return; } EntityHitResult hitResult = result.get(); - if (optionalCustomitem.isPresent() && !optionalCustomitem.get().behaviors().isEmpty()) { - for (ItemBehavior behavior : optionalCustomitem.get().behaviors()) { + if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { + for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { if (behavior instanceof FurnitureItemBehavior) { behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); return; @@ -1604,7 +1627,12 @@ public class PacketConsumers { } // now simulate vanilla item behavior serverPlayer.setResendSound(); - FastNMS.INSTANCE.simulateInteraction(serverPlayer.serverPlayer(), DirectionUtils.toNMSDirection(hitResult.direction()), hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, LocationUtils.toBlockPos(hitResult.blockPos())); + FastNMS.INSTANCE.simulateInteraction( + serverPlayer.serverPlayer(), + DirectionUtils.toNMSDirection(hitResult.direction()), + hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, + LocationUtils.toBlockPos(hitResult.blockPos()) + ); } else { furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { if (furniture.tryOccupySeat(seatPos)) { @@ -1612,8 +1640,29 @@ public class PacketConsumers { } }); } + }; + } else if (actionType == 0) { + int hand = buf.readVarInt(); + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeVarInt(hand); + buf.writeBoolean(usingSecondaryAction); } - }, player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); + return; + } else { + return; + } + + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); + } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e); } 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 41679b5a6..678e06f1a 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 @@ -57,4 +57,6 @@ public interface PacketIds { int serverboundContainerClickPacket(); int serverboundSetCreativeModeSlotPacket(); + + int serverboundInteractPacket(); } 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 c106da9f2..d9ff6e609 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 @@ -144,4 +144,9 @@ public class PacketIds1_20 implements PacketIds { public int clientboundBlockEventPacket() { return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockEventPacket); } + + @Override + public int serverboundInteractPacket() { + return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket); + } } 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 afefc4407..03d66538a 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 @@ -143,4 +143,9 @@ public class PacketIds1_20_5 implements PacketIds { public int serverboundSetCreativeModeSlotPacket() { return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); } + + @Override + public int serverboundInteractPacket() { + return PacketIdFinder.serverboundByName("minecraft:interact"); + } }