From 0eef225da6b25e9ba7ac807f2b85765b97b89098 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 16:00:44 +0800 Subject: [PATCH 1/6] Update BukkitServerPlayer.java --- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index b1ce6b3ae..deec8e1cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -681,7 +681,7 @@ public class BukkitServerPlayer extends Player { double d1 = (double) hitPos.y() - otherLocation.getY(); double d2 = (double) hitPos.z() - otherLocation.getZ(); if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { - this.plugin.networkManager().sendPacket(this.plugin.adapt(other), packet); + FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(other)), packet); } } } From a5d6ce8107cc5c1e3e9297dec8218edff7451b25 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 19:33:57 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0dyed-color?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 5 +- .../plugin/injector/BlockGenerator.java | 4 ++ .../plugin/network/PacketConsumers.java | 4 +- .../core/item/AbstractItemManager.java | 9 ++++ .../core/item/modifier/DyedColorModifier.java | 48 +++++++++++++++++++ gradle.properties | 2 +- 6 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 6e5c77ea3..f118b8236 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.RegistryUtils; @@ -161,8 +162,8 @@ public class BukkitBlockManager extends AbstractBlockManager { list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue())); } Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, list)); - for (Player player : Bukkit.getOnlinePlayers()) { - this.plugin.networkManager().sendPacket(this.plugin.adapt(player), packet); + for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) { + player.sendPacket(packet, false); } // 如果空,那么新来的玩家就没必要收到更新包了 if (list.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java index 0b349fca0..e6b543954 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java @@ -179,6 +179,10 @@ public final class BlockGenerator { if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) { startNoteBlockChain(args); } + } else if (indicator.isTripwire()) { + if (CoreReflections.clazz$ServerLevel.isInstance(args[posIndex])) { + + } } try { return holder.value().updateShape(thisObj, args, superMethod); 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 ce714fa41..f79e6800f 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 @@ -1106,13 +1106,13 @@ public class PacketConsumers { Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); BlockPos pos = LocationUtils.fromBlockPos(blockPos); if (VersionHelper.isFolia()) { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { try { handlePlayerActionPacketOnMainThread(player, world, pos, packet); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); } - }, world, pos.x() >> 4, pos.z() >> 4); + }, () -> {}); } else { handlePlayerActionPacketOnMainThread(player, world, pos, packet); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 3e413ffc0..10364c0fb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -27,6 +27,7 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.type.Either; +import org.joml.Vector3f; import java.nio.file.Path; import java.util.*; @@ -459,6 +460,14 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } return new DynamicLoreModifier<>(dynamicLore); }, "dynamic-lore"); + registerDataFunction((obj) -> { + if (obj instanceof Integer integer) { + return new DyedColorModifier<>(integer); + } else { + Vector3f vector3f = MiscUtils.getAsVector3f(obj, "dyed-color"); + return new DyedColorModifier<>(MCUtils.fastFloor(vector3f.x) << 16 + MCUtils.fastFloor(vector3f.y) << 8 + MCUtils.fastFloor(vector3f.z)); + } + }, "dyed-color"); registerDataFunction((obj) -> { Map data = MiscUtils.castToMap(obj, false); return new TagsModifier<>(data); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java new file mode 100644 index 000000000..0ef63fe0c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Color; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +public class DyedColorModifier implements ItemDataModifier { + private final int color; + + public DyedColorModifier(int color) { + this.color = color; + } + + @Override + public String name() { + return "dyed-color"; + } + + @Override + public void apply(Item item, ItemBuildContext context) { + item.dyedColor(this.color); + } + + @Override + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.DYED_COLOR); + if (previous != null) { + networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("display", "color"); + if (previous != null) { + networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } +} diff --git a/gradle.properties b/gradle.properties index de7167077..f71f57228 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.56.2 +project_version=0.0.56.3 config_version=34 lang_version=15 project_group=net.momirealms From 959515d0239bb1db966222496b0a2bc474afbf54 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 19:54:25 +0800 Subject: [PATCH 3/6] =?UTF-8?q?food=E5=92=8C=E8=BF=94=E8=BF=98=E7=89=A9?= =?UTF-8?q?=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/listener/ItemEventListener.java | 35 +++++++++++++++++-- .../bukkit/plugin/BukkitCraftEngine.java | 1 + .../craftengine/core/item/ItemSettings.java | 13 +++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 21436d077..d43d0649f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -15,12 +15,12 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.item.setting.FoodData; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.Cancellable; -import net.momirealms.craftengine.core.util.Direction; +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.Vec3d; @@ -33,6 +33,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EquipmentSlot; @@ -329,6 +330,36 @@ public class ItemEventListener implements Listener { if (event.isCancelled()) { return; } + if (event.getPlayer().getGameMode() != GameMode.CREATIVE) { + Key replacement = customItem.settings().consumeReplacement(); + if (replacement == null) { + event.setReplacement(null); + } else { + ItemStack replacementItem = this.plugin.itemManager().buildItemStack(replacement, this.plugin.adapt(event.getPlayer())); + event.setReplacement(replacementItem); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) + public void onFoodLevelChange(FoodLevelChangeEvent event) { + if (VersionHelper.isOrAbove1_20_5()) return; + if (!(event.getEntity() instanceof Player player)) return; + ItemStack consumedItem = event.getItem(); + if (ItemUtils.isEmpty(consumedItem)) return; + Item wrapped = this.plugin.itemManager().wrap(consumedItem); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + return; + } + CustomItem customItem = optionalCustomItem.get(); + FoodData foodData = customItem.settings().foodData(); + if (foodData == null) return; + event.setCancelled(true); + int oldFoodLevel = player.getFoodLevel(); + if (foodData.nutrition() != 0) player.setFoodLevel(MCUtils.clamp(oldFoodLevel + foodData.nutrition(), 0, 20)); + float oldSaturation = player.getSaturation(); + if (foodData.saturation() != 0) player.setSaturation(MCUtils.clamp(oldSaturation, 0, 10)); } private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index d00647089..7902e8216 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -48,6 +48,7 @@ import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.jspecify.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index d8cae1654..9bf01f99a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -36,6 +36,7 @@ public class ItemSettings { boolean dyeable = true; Helmet helmet = null; FoodData foodData = null; + Key consumeReplacement = null; private ItemSettings() {} @@ -72,6 +73,7 @@ public class ItemSettings { newSettings.dyeable = settings.dyeable; newSettings.helmet = settings.helmet; newSettings.foodData = settings.foodData; + newSettings.consumeReplacement = settings.consumeReplacement; return newSettings; } @@ -124,6 +126,11 @@ public class ItemSettings { return foodData; } + @Nullable + public Key consumeReplacement() { + return consumeReplacement; + } + @Nullable public Helmet helmet() { return helmet; @@ -139,6 +146,11 @@ public class ItemSettings { return this; } + public ItemSettings consumeReplacement(Key key) { + this.consumeReplacement = key; + return this; + } + public ItemSettings canRepair(boolean canRepair) { this.canRepair = canRepair; return this; @@ -228,6 +240,7 @@ public class ItemSettings { int intValue = ResourceConfigUtils.getAsInt(value, "fuel-time"); return settings -> settings.fuelTime(intValue); })); + registerFactory("consume-replacement", (value -> settings -> settings.consumeReplacement(Key.of(value.toString())))); registerFactory("tags", (value -> { List tags = MiscUtils.getAsStringList(value); return settings -> settings.tags(tags.stream().map(Key::of).collect(Collectors.toSet())); From 37e4682c8e6c0ba9481e953a795bcee9d698bf4d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 20:03:26 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BA=A4=E4=BA=92=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E8=A7=A6=E5=8F=91right=20click?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/listener/ItemEventListener.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index d43d0649f..0bec09f6b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -34,6 +34,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EquipmentSlot; @@ -50,6 +51,28 @@ public class ItemEventListener implements Listener { this.plugin = plugin; } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onInteractEntity(PlayerInteractEntityEvent event) { + BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer()); + if (serverPlayer == null) return; + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + Item itemInHand = serverPlayer.getItemInHand(hand); + + if (itemInHand == null) return; + Optional> optionalCustomItem = itemInHand.getCustomItem(); + if (optionalCustomItem.isEmpty()) return; + + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) + .withParameter(DirectContextParameters.HAND, hand) + ); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onInteractBlock(PlayerInteractEvent event) { Action action = event.getAction(); @@ -63,6 +86,7 @@ public class ItemEventListener implements Listener { } BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; // 如果本tick内主手已被处理,则不处理副手 // 这是因为客户端可能会同时发主副手交互包,但实际上只能处理其中一个 From 5e447505efa55cc466ba35383789b2f921eacd63 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 21:00:11 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E4=BA=A4=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"); + } } From b362dc03d3464f93c61d28fb067bde514a60f064 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 8 Jun 2025 22:36:56 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D1.20-1.20.6=E7=A2=B0?= =?UTF-8?q?=E6=92=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/block/BukkitBlockManager.java | 1 - .../craftengine/bukkit/plugin/BukkitCraftEngine.java | 1 - .../bukkit/plugin/network/PacketConsumers.java | 6 ++++-- .../bukkit/plugin/user/BukkitServerPlayer.java | 12 +++++++----- .../core/item/modifier/DyedColorModifier.java | 2 -- gradle.properties | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index f118b8236..d9853e3c9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -45,7 +45,6 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 7902e8216..d00647089 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -48,7 +48,6 @@ import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.command.CommandSender; -import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import org.jspecify.annotations.Nullable; 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 00fa3d042..14f12a171 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,7 +50,10 @@ 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.*; +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.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; @@ -58,7 +61,6 @@ 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; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index deec8e1cc..ca5ac25de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -558,6 +558,8 @@ public class BukkitServerPlayer extends Player { int currentTick = gameTicks(); // optimize break speed, otherwise it would be too fast if (currentTick - this.lastSuccessfulBreak <= 5) return; + Object destroyedState = this.destroyedState; + if (destroyedState == null) return; try { org.bukkit.entity.Player player = platformPlayer(); double range = getCachedInteractionRange(); @@ -575,7 +577,7 @@ public class BukkitServerPlayer extends Player { // send hit sound if the sound is removed if (currentTick - this.lastHitBlockTime > 3) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(this.destroyedState); + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(destroyedState); Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(blockOwner); Object soundEvent = CoreReflections.field$SoundType$hitSound.get(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); @@ -601,8 +603,8 @@ public class BukkitServerPlayer extends Player { } } - float progressToAdd = getDestroyProgress(this.destroyedState, hitPos); - int id = BlockStateUtils.blockStateToId(this.destroyedState); + float progressToAdd = getDestroyProgress(destroyedState, hitPos); + int id = BlockStateUtils.blockStateToId(destroyedState); ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(id); // double check custom block if (customState != null && !customState.isEmpty()) { @@ -612,13 +614,13 @@ public class BukkitServerPlayer extends Player { // it's correct on plugin side if (blockSettings.isCorrectTool(item.id())) { // but not on serverside - if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) { + if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { // we fix the speed progressToAdd = progressToAdd * (10f / 3f); } } else { // not a correct tool on plugin side and not a correct tool on serverside - if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) { + if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { progressToAdd = progressToAdd * (10f / 3f) * blockSettings.incorrectToolSpeed(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java index 0ef63fe0c..7b640c69a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java @@ -4,8 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; diff --git a/gradle.properties b/gradle.properties index f71f57228..6e47516b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -51,7 +51,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.16 +nms_helper_version=0.66.17 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23