From 65852ee0a221528af043826791d5b9f42011026b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 11 Jun 2025 04:04:31 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=9B=9E=E9=80=80=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/BukkitFurniture.java | 22 ---- .../furniture/BukkitFurnitureManager.java | 2 - .../furniture/FurnitureEventListener.java | 4 - .../bukkit/item/ComponentItemWrapper.java | 2 - .../plugin/network/BukkitNetworkManager.java | 1 + .../plugin/network/PacketConsumers.java | 62 ++++++---- .../FurnitureCollisionPacketHandler.java | 19 +++ .../handler/FurniturePacketHandler.java | 12 ++ .../minecraft/NetworkReflections.java | 116 +++++++++--------- .../src/main/resources/translations/en.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 2 +- .../core/pack/AbstractPackManager.java | 4 +- .../template/ExpressionTemplateArgument.java | 2 +- .../plugin/network/EntityPacketHandler.java | 3 + 14 files changed, 136 insertions(+), 117 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index 3531c73fa..7002c5216 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -28,7 +28,6 @@ import org.joml.Vector3f; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.*; -import java.util.function.Consumer; public class BukkitFurniture implements Furniture { private final Key id; @@ -131,7 +130,6 @@ public class BukkitFurniture implements Furniture { Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); for (Collider entity : this.colliderEntities) { FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity.handle()); - injectFurnitureEntity(entity.handle()); Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity.handle()); bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1); } @@ -361,24 +359,4 @@ public class BukkitFurniture implements Furniture { newLocation.add(offset.x, offset.y + 0.6, -offset.z); return newLocation; } - - public static void injectFurnitureEntity(Object nmsEntity) { - try { - Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); - Object serverEntity = FastNMS.INSTANCE.field$ChunkMap$TrackedEntity$serverEntity(trackedEntity); - CoreReflections.handle$ServerEntity$broadcastSetter.invokeExact(serverEntity, Handlers.DO_NOTHING); - CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(serverEntity, Integer.MAX_VALUE); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to inject collider", e); - } - } - - @FunctionalInterface - public interface Handlers extends Consumer { - Consumer DO_NOTHING = doNothing(); - - static Handlers doNothing() { - return (packet) -> {}; - } - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 431f81ac1..2841ed4d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -86,7 +86,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { SoundData data = furniture.settings().sounds().placeSound(); location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch()); } - BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(furnitureEntity)); return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); } @@ -102,7 +101,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { for (Entity entity : entities) { if (entity instanceof ItemDisplay display) { handleBaseEntityLoadEarly(display); - BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(display)); } else if (entity instanceof Interaction interaction) { handleCollisionEntityLoadOnEntitiesLoad(interaction); } else if (entity instanceof Boat boat) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java index e9ffadda8..f9c526233 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.ItemDisplay; @@ -37,7 +36,6 @@ public class FurnitureEventListener implements Listener { for (Entity entity : entities) { if (entity instanceof ItemDisplay itemDisplay) { this.manager.handleBaseEntityLoadEarly(itemDisplay); - BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay)); } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity); } @@ -50,7 +48,6 @@ public class FurnitureEventListener implements Listener { for (Entity entity : entities) { if (entity instanceof ItemDisplay itemDisplay) { this.manager.handleBaseEntityLoadEarly(itemDisplay); - BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay)); } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity); } @@ -62,7 +59,6 @@ public class FurnitureEventListener implements Listener { Entity entity = event.getEntity(); if (entity instanceof ItemDisplay itemDisplay) { this.manager.handleBaseEntityLoadLate(itemDisplay, 0); - BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay)); } else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) { this.manager.handleCollisionEntityLoadLate(entity, 0); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index f0f1b2ffd..fefddcf71 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; import net.momirealms.craftengine.core.item.ItemWrapper; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; @@ -113,7 +112,6 @@ public class ComponentItemWrapper implements ItemWrapper { if (value == null) return; Object componentType = ensureDataComponentType(type); if (componentType == null) { - TranslationManager.instance().log("warning.config.item.component_notfound", type.toString()); return; } Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); 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 7794714ca..67b311d66 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 @@ -159,6 +159,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); 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 95573e573..ea3ba7743 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 @@ -162,6 +162,7 @@ public class PacketConsumers { BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); if (furniture != null) { event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); } }; ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { @@ -172,6 +173,7 @@ public class PacketConsumers { BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); if (furniture != null) { event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); } }; } @@ -1169,14 +1171,14 @@ public class PacketConsumers { public static final TriConsumer HELLO_C2S = (user, event, packet) -> { try { BukkitServerPlayer player = (BukkitServerPlayer) user; - String name = (String) NetworkReflections.handle$ServerboundHelloPacket$nameGetter.invokeExact(packet); + String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); player.setName(name); if (VersionHelper.isOrAbove1_20_2()) { - UUID uuid = (UUID) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); player.setUUID(uuid); } else { @SuppressWarnings("unchecked") - Optional uuid = (Optional) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + Optional uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); if (uuid.isPresent()) { player.setUUID(uuid.get()); } else { @@ -1220,10 +1222,10 @@ public class PacketConsumers { player.clearView(); Object dimensionKey; if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.handle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); } else { - Object commonInfo = NetworkReflections.handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); } Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); @@ -1248,10 +1250,10 @@ public class PacketConsumers { if (BukkitNetworkManager.hasViaVersion()) { user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid())); } - dimensionKey = NetworkReflections.handle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); } else { - Object commonInfo = NetworkReflections.handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); } Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); @@ -1295,9 +1297,9 @@ public class PacketConsumers { Player bukkitPlayer = player.platformPlayer(); if (bukkitPlayer == null) return; if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; - int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet); + int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet); if (slot < 36 || slot > 44) return; - ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); + ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); if (ItemUtils.isEmpty(item)) return; if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { return; @@ -1370,7 +1372,7 @@ public class PacketConsumers { if (!user.isOnline()) return; Player player = (Player) user.platformPlayer(); if (player == null) return; - Object pos = NetworkReflections.handle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); + Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); if (VersionHelper.isFolia()) { int x = FastNMS.INSTANCE.field$Vec3i$x(pos); int z = FastNMS.INSTANCE.field$Vec3i$z(pos); @@ -1408,7 +1410,7 @@ public class PacketConsumers { // 1.21.4+ public static final TriConsumer PICK_ITEM_FROM_ENTITY = (user, event, packet) -> { try { - int entityId = (int) NetworkReflections.handle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); + int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Player player = (Player) user.platformPlayer(); @@ -1747,14 +1749,14 @@ public class PacketConsumers { if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { return; } - String message = (String) NetworkReflections.handle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); + String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); if (message != null && !message.isEmpty()) { // check bypass FontManager manager = CraftEngine.instance().fontManager(); IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); if (result.has()) { try { - NetworkReflections.handle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); + NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); } catch (ReflectiveOperationException e) { CraftEngine.instance().logger().warn("Failed to replace chat", e); } @@ -1773,7 +1775,7 @@ public class PacketConsumers { if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { return; } - String[] lines = (String[]) NetworkReflections.handle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); + String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); FontManager manager = CraftEngine.instance().fontManager(); if (!manager.isDefaultFontInUse()) return; for (int i = 0; i < lines.length; i++) { @@ -1804,9 +1806,9 @@ public class PacketConsumers { boolean changed = false; - List pages = (List) NetworkReflections.handleServerboundEditBookPacket$pagesGetter.invokeExact(packet); + List pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); List newPages = new ArrayList<>(pages.size()); - Optional title = (Optional) NetworkReflections.handle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); + Optional title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); Optional newTitle; if (title.isPresent()) { @@ -1830,7 +1832,7 @@ public class PacketConsumers { if (changed) { Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( - (int) NetworkReflections.handle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), + (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), newPages, newTitle ); @@ -1863,7 +1865,7 @@ public class PacketConsumers { public static final TriConsumer CUSTOM_PAYLOAD = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_5()) return; - Object payload = NetworkReflections.handle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { Payload discardedPayload = DiscardedPayload.from(payload); if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) @@ -2282,7 +2284,7 @@ public class PacketConsumers { public static final TriConsumer HANDSHAKE_C2S = (user, event, packet) -> { try { if (BukkitNetworkManager.hasViaVersion()) return; - int protocolVersion = (int) NetworkReflections.handle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet); + int protocolVersion = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet); user.setProtocolVersion(protocolVersion); } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e); @@ -2302,7 +2304,7 @@ public class PacketConsumers { public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { try { if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return; - Object action = NetworkReflections.handle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet); + Object action = NetworkReflections.methodHandle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet); if (action == null) return; if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) { @@ -2324,9 +2326,9 @@ public class PacketConsumers { try { Object player = user.serverPlayer(); if (player == null) return; - int entityId = (int) NetworkReflections.handle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); + int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; - byte eventId = (byte) NetworkReflections.handle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); + byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); if (eventId >= 24 && eventId <= 28) { CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); } @@ -2346,4 +2348,16 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); } }; + + public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { + try { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMove(user, event, packet); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java new file mode 100644 index 000000000..63332219f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public class FurnitureCollisionPacketHandler implements EntityPacketHandler { + public static final FurnitureCollisionPacketHandler INSTANCE = new FurnitureCollisionPacketHandler(); + + @Override + public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } + + @Override + public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java index 70c0d6778..0a60cfc3a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java @@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import it.unimi.dsi.fastutil.ints.IntList; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import java.util.List; @@ -17,4 +19,14 @@ public class FurniturePacketHandler implements EntityPacketHandler { entityIds.addAll(this.fakeEntities); return true; } + + @Override + public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } + + @Override + public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 156a91c0a..2b0498e8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1304,165 +1304,165 @@ public final class NetworkReflections { ) ); - public static final MethodHandle handle$ServerboundRenameItemPacket$nameGetter; - public static final MethodHandle handle$ServerboundRenameItemPacket$nameSetter; - public static final MethodHandle handle$ServerboundHelloPacket$nameGetter; - public static final MethodHandle handle$ServerboundHelloPacket$uuidGetter; - public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter; - public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter; - public static final MethodHandle handle$ServerboundInteractPacket$actionGetter; - public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter; - public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter; - public static final MethodHandle handle$ServerboundSignUpdatePacket$linesGetter; - public static final MethodHandle handleServerboundEditBookPacket$pagesGetter; - public static final MethodHandle handle$ServerboundEditBookPacket$titleGetter; - public static final MethodHandle handle$ServerboundEditBookPacket$slotGetter; - public static final MethodHandle handle$ServerboundResourcePackPacket$actionGetter; - public static final MethodHandle handle$ClientboundEntityEventPacket$entityIdGetter; - public static final MethodHandle handle$ClientboundEntityEventPacket$eventIdGetter; - public static final MethodHandle handle$ClientIntentionPacket$protocolVersionGetter; - public static final MethodHandle handle$ClientboundRespawnPacket$dimensionGetter; - public static final MethodHandle handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter; - public static final MethodHandle handle$CommonPlayerSpawnInfo$dimensionGetter; - public static final MethodHandle handle$ClientboundLoginPacket$dimensionGetter; - public static final MethodHandle handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter; - public static final MethodHandle handle$ServerboundPickItemFromBlockPacket$posGetter; - public static final MethodHandle handle$ServerboundPickItemFromEntityPacket$idGetter; - public static final MethodHandle handle$ServerboundCustomPayloadPacket$payloadGetter; + public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameGetter; + public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameSetter; + public static final MethodHandle methodHandle$ServerboundHelloPacket$nameGetter; + public static final MethodHandle methodHandle$ServerboundHelloPacket$uuidGetter; + public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter; + public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$actionGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter; + public static final MethodHandle methodHandle$ServerboundSignUpdatePacket$linesGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$pagesGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$titleGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$slotGetter; + public static final MethodHandle methodHandle$ServerboundResourcePackPacket$actionGetter; + public static final MethodHandle methodHandle$ClientboundEntityEventPacket$entityIdGetter; + public static final MethodHandle methodHandle$ClientboundEntityEventPacket$eventIdGetter; + public static final MethodHandle methodHandle$ClientIntentionPacket$protocolVersionGetter; + public static final MethodHandle methodHandle$ClientboundRespawnPacket$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter; + public static final MethodHandle methodHandle$CommonPlayerSpawnInfo$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundLoginPacket$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter; + public static final MethodHandle methodHandle$ServerboundPickItemFromBlockPacket$posGetter; + public static final MethodHandle methodHandle$ServerboundPickItemFromEntityPacket$idGetter; + public static final MethodHandle methodHandle$ServerboundCustomPayloadPacket$payloadGetter; static { try { - handle$ServerboundRenameItemPacket$nameGetter = requireNonNull( + methodHandle$ServerboundRenameItemPacket$nameGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundRenameItemPacket$name) .asType(MethodType.methodType(String.class, Object.class)) ); - handle$ServerboundRenameItemPacket$nameSetter = requireNonNull( + methodHandle$ServerboundRenameItemPacket$nameSetter = requireNonNull( ReflectionUtils.unreflectSetter(field$ServerboundRenameItemPacket$name) .asType(MethodType.methodType(void.class, Object.class, String.class)) ); - handle$ServerboundHelloPacket$nameGetter = requireNonNull( + methodHandle$ServerboundHelloPacket$nameGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$name) .asType(MethodType.methodType(String.class, Object.class)) ); - handle$ServerboundHelloPacket$uuidGetter = requireNonNull( + methodHandle$ServerboundHelloPacket$uuidGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$uuid) .asType(MethodType.methodType(VersionHelper.isOrAbove1_20_2() ? UUID.class : Optional.class, Object.class)) ); - handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull( + methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$itemStack) .asType(MethodType.methodType(Object.class, Object.class)) ); - handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull( + methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$slotNum) .asType(MethodType.methodType(VersionHelper.isOrAbove1_20_5() ? short.class : int.class, Object.class)) ); - handle$ServerboundInteractPacket$actionGetter = requireNonNull( + methodHandle$ServerboundInteractPacket$actionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$action) .asType(MethodType.methodType(Object.class, Object.class)) ); - handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull( + methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$hand) .asType(MethodType.methodType(Object.class, Object.class)) ); - handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull( + methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$location) .asType(MethodType.methodType(Object.class, Object.class)) ); - handle$ServerboundSignUpdatePacket$linesGetter = requireNonNull( + methodHandle$ServerboundSignUpdatePacket$linesGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundSignUpdatePacket$lines) .asType(MethodType.methodType(String[].class, Object.class)) ); - handleServerboundEditBookPacket$pagesGetter = requireNonNull( + methodHandle$ServerboundEditBookPacket$pagesGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$pages) .asType(MethodType.methodType(List.class, Object.class)) ); - handle$ServerboundEditBookPacket$titleGetter = requireNonNull( + methodHandle$ServerboundEditBookPacket$titleGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$title) .asType(MethodType.methodType(Optional.class, Object.class)) ); - handle$ServerboundEditBookPacket$slotGetter = requireNonNull( + methodHandle$ServerboundEditBookPacket$slotGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot) .asType(MethodType.methodType(int.class, Object.class)) ); - handle$ServerboundResourcePackPacket$actionGetter = requireNonNull( + methodHandle$ServerboundResourcePackPacket$actionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action) .asType(MethodType.methodType(Object.class, Object.class)) ); - handle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull( + methodHandle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId) .asType(MethodType.methodType(int.class, Object.class)) ); - handle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull( + methodHandle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$eventId) .asType(MethodType.methodType(byte.class, Object.class)) ); - handle$ClientIntentionPacket$protocolVersionGetter = requireNonNull( + methodHandle$ClientIntentionPacket$protocolVersionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientIntentionPacket$protocolVersion) .asType(MethodType.methodType(int.class, Object.class)) ); if (field$ServerboundCustomPayloadPacket$payload != null) { - handle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull( + methodHandle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundCustomPayloadPacket$payload) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ServerboundCustomPayloadPacket$payloadGetter = null; + methodHandle$ServerboundCustomPayloadPacket$payloadGetter = null; } if (field$ServerboundPickItemFromEntityPacket$id != null) { - handle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull( + methodHandle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromEntityPacket$id) .asType(MethodType.methodType(int.class, Object.class)) ); } else { - handle$ServerboundPickItemFromEntityPacket$idGetter = null; + methodHandle$ServerboundPickItemFromEntityPacket$idGetter = null; } if (field$ServerboundPickItemFromBlockPacket$pos != null) { - handle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull( + methodHandle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromBlockPacket$pos) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ServerboundPickItemFromBlockPacket$posGetter = null; + methodHandle$ServerboundPickItemFromBlockPacket$posGetter = null; } if (field$ClientboundLoginPacket$commonPlayerSpawnInfo != null) { - handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull( + methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$commonPlayerSpawnInfo) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null; + methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null; } if (field$ClientboundLoginPacket$dimension != null) { - handle$ClientboundLoginPacket$dimensionGetter = requireNonNull( + methodHandle$ClientboundLoginPacket$dimensionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$dimension) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ClientboundLoginPacket$dimensionGetter = null; + methodHandle$ClientboundLoginPacket$dimensionGetter = null; } if (field$CommonPlayerSpawnInfo$dimension != null) { - handle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull( + methodHandle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$CommonPlayerSpawnInfo$dimension) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$CommonPlayerSpawnInfo$dimensionGetter = null; + methodHandle$CommonPlayerSpawnInfo$dimensionGetter = null; } if (field$ClientboundRespawnPacket$commonPlayerSpawnInfo != null) { - handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull( + methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$commonPlayerSpawnInfo) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null; + methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null; } if (field$ClientboundRespawnPacket$dimension != null) { - handle$ClientboundRespawnPacket$dimensionGetter = requireNonNull( + methodHandle$ClientboundRespawnPacket$dimensionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$dimension) .asType(MethodType.methodType(Object.class, Object.class)) ); } else { - handle$ClientboundRespawnPacket$dimensionGetter = null; + methodHandle$ClientboundRespawnPacket$dimensionGetter = null; } } catch (Throwable e) { throw new ReflectionInitException("Failed to initialize reflection", e); diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index a2b68568f..8a94e2de3 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -158,7 +158,7 @@ warning.config.item.invalid_material: "Issue found in file - The warning.config.item.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." warning.config.item.bad_custom_model_data: "Issue found in file - The item '' is using a custom model data '' that is too large. It's recommended to use a value lower than 16,777,216." warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data '' that has been occupied by item ''." -warning.config.item.component_notfound: "Issue found - Have item using a component '' that does not exist." +warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." warning.config.item.behavior.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for its item behavior." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 4f11d3878..506c5b9ab 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -158,7 +158,7 @@ warning.config.item.invalid_material: "在文件 发现问题 - warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''." warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" -warning.config.item.component_notfound: "发现问题 - 有物品使用了未知的组件 ''" +warning.config.item.invalid_component: "在文件 发现问题 - 物品 '' 使用了未知的数据组件 ''" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" warning.config.item.behavior.missing_type: "在文件 发现问题 - 物品 '' 的行为配置缺少必需的 'type' 参数" diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 74f195b60..55c1244a8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.pack; -import com.google.common.collect.*; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.google.gson.*; @@ -21,7 +22,6 @@ import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.pack.obfuscation.ObfA; -import net.momirealms.craftengine.core.pack.obfuscation.ObfH; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java index b2da9c6a9..a92d6fdf2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java @@ -50,7 +50,7 @@ public class ExpressionTemplateArgument implements TemplateArgument { } public Function formatter() { - return formatter; + return this.formatter; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java index 224a27f81..15e0aa919 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java @@ -16,4 +16,7 @@ public interface EntityPacketHandler { default void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { } + + default void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + } } From 6adf7de9a4197c52e8e66affed5b72c9aeefd95d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 11 Jun 2025 19:02:48 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectile/BukkitProjectileManager.java | 2 +- .../plugin/network/BukkitNetworkManager.java | 2 +- .../plugin/network/PacketConsumers.java | 4 +- .../reflection/minecraft/CoreReflections.java | 12 +- .../resources/default/configuration/emoji.yml | 2 +- .../resources/default/configuration/items.yml | 76 ++-- .../default/configuration/templates.yml | 350 +++++++++--------- .../resources/internal/configuration/gui.yml | 12 +- .../craftengine/core/item/ItemSettings.java | 10 +- .../config/template/TemplateManager.java | 70 ++-- .../plugin/context/AbstractCommonContext.java | 2 +- .../plugin/context/PlayerOptionalContext.java | 2 +- .../core/plugin/context/ViewerContext.java | 12 +- .../text/minimessage/PlaceholderTag.java | 14 +- .../minimessage/RelationalPlaceholderTag.java | 12 +- .../minimessage/ViewerPlaceholderTag.java | 5 +- .../core/util/AdventureHelper.java | 5 + .../craftengine/core/util/MiscUtils.java | 2 +- gradle.properties | 4 +- 19 files changed, 305 insertions(+), 293 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 90b3760be..a36e23b0e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -205,7 +205,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { private void updateProjectileUpdateInterval(int updateInterval) { if (this.lastInjectedInterval == updateInterval) return; try { - CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval); + CoreReflections.methodHandle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval); this.lastInjectedInterval = updateInterval; } catch (Throwable e) { BukkitProjectileManager.this.plugin.logger().warn("Failed to update server entity update interval for " + this.projectile.getType().getKey() + "[" + this.projectile.getUniqueId() + "]", e); 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 67b311d66..b69f40300 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 @@ -82,7 +82,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String CONNECTION_HANDLER_NAME = "craftengine_connection_handler"; private static final String SERVER_CHANNEL_HANDLER_NAME = "craftengine_server_channel_handler"; - private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_packet_handler"; + private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_channel_handler"; private static final String PACKET_ENCODER = "craftengine_encoder"; private static final String PACKET_DECODER = "craftengine_decoder"; 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 ea3ba7743..a6762d938 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 @@ -1452,11 +1452,11 @@ public class PacketConsumers { assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; if (VersionHelper.isOrAbove1_21_5()) { CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); } else { CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 6371c5b08..e8cf86bb1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3274,21 +3274,21 @@ public final class CoreReflections { ) ); - public static final MethodHandle handle$ServerEntity$broadcastSetter; - public static final MethodHandle handle$ServerEntity$updateIntervalSetter; - public static final MethodHandle handle$ServerPlayer$connectionGetter; + public static final MethodHandle methodHandle$ServerEntity$broadcastSetter; + public static final MethodHandle methodHandle$ServerEntity$updateIntervalSetter; + public static final MethodHandle methodHandle$ServerPlayer$connectionGetter; static { try { - handle$ServerEntity$broadcastSetter = requireNonNull( + methodHandle$ServerEntity$broadcastSetter = requireNonNull( ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast) .asType(MethodType.methodType(void.class, Object.class, Consumer.class)) ); - handle$ServerEntity$updateIntervalSetter = requireNonNull( + methodHandle$ServerEntity$updateIntervalSetter = requireNonNull( ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval) .asType(MethodType.methodType(void.class, Object.class, int.class)) ); - handle$ServerPlayer$connectionGetter = requireNonNull( + methodHandle$ServerPlayer$connectionGetter = requireNonNull( ReflectionUtils.unreflectGetter(field$ServerPlayer$connection) .asType(MethodType.methodType(Object.class, Object.class)) ); diff --git a/common-files/src/main/resources/resources/default/configuration/emoji.yml b/common-files/src/main/resources/resources/default/configuration/emoji.yml index 996057731..95dda77c6 100644 --- a/common-files/src/main/resources/resources/default/configuration/emoji.yml +++ b/common-files/src/main/resources/resources/default/configuration/emoji.yml @@ -2,7 +2,7 @@ templates: default:emoji/basic: content: "'>" default:emoji/addition_info: - content: "'>{text}" + content: "'>${text}" emoji: default:emoji_location: diff --git a/common-files/src/main/resources/resources/default/configuration/items.yml b/common-files/src/main/resources/resources/default/configuration/items.yml index eb329e847..5d2b4ba4c 100644 --- a/common-files/src/main/resources/resources/default/configuration/items.yml +++ b/common-files/src/main/resources/resources/default/configuration/items.yml @@ -229,16 +229,16 @@ items#topaz_gears: templates: default:armor/topaz: - material: "chainmail_{part}" + material: "chainmail_${part}" custom-model-data: 1000 data: - item-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz settings: tags: - "default:topaz_tools" equippable: - slot: "{slot}" + slot: "${slot}" asset-id: topaz humanoid: "minecraft:topaz" humanoid-leggings: "minecraft:topaz" @@ -247,111 +247,111 @@ templates: property: minecraft:trim_material fallback: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}" + path: "minecraft:item/custom/topaz_${part}" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" + "layer0": "minecraft:item/custom/topaz_${part}" cases: - when: minecraft:quartz model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_quartz_trim" + path: "minecraft:item/custom/topaz_${part}_quartz_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_quartz" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_quartz" - when: minecraft:iron model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_iron_trim" + path: "minecraft:item/custom/topaz_${part}_iron_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_iron" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_iron" - when: minecraft:netherite model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_netherite_trim" + path: "minecraft:item/custom/topaz_${part}_netherite_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_netherite" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_netherite" - when: minecraft:redstone model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_redstone_trim" + path: "minecraft:item/custom/topaz_${part}_redstone_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_redstone" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_redstone" - when: minecraft:copper model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_copper_trim" + path: "minecraft:item/custom/topaz_${part}_copper_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_copper" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_copper" - when: minecraft:gold model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_gold_trim" + path: "minecraft:item/custom/topaz_${part}_gold_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_gold" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_gold" - when: minecraft:emerald model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_emerald_trim" + path: "minecraft:item/custom/topaz_${part}_emerald_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_emerald" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_emerald" - when: minecraft:diamond model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_diamond_trim" + path: "minecraft:item/custom/topaz_${part}_diamond_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_diamond" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_diamond" - when: minecraft:lapis model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_lapis_trim" + path: "minecraft:item/custom/topaz_${part}_lapis_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_lapis" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_lapis" - when: minecraft:amethyst model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_amethyst_trim" + path: "minecraft:item/custom/topaz_${part}_amethyst_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_amethyst" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_amethyst" - when: minecraft:resin model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_resin_trim" + path: "minecraft:item/custom/topaz_${part}_resin_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_resin" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_resin" recipes#11: default:topaz_shovel: diff --git a/common-files/src/main/resources/resources/default/configuration/templates.yml b/common-files/src/main/resources/resources/default/configuration/templates.yml index d6e8db003..73324b0ed 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -7,32 +7,32 @@ templates#models#block: # model: model_path # texture: texture_path default:model/cube_all: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_all" textures: - "all": "{texture}" + "all": "${texture}" # template: default:model/simplified_cube_all # arguments: # path: [model/texture]_path default:model/simplified_cube_all: - path: "{path}" + path: "${path}" generation: parent: "minecraft:block/cube_all" textures: - "all": "{path}" + "all": "${path}" # template: default:model/cube_column # arguments: # model: model_path # end_texture: end_texture_path # side_texture: side_texture_path default:model/cube_column: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_column" textures: - "end": "{end_texture}" - "side": "{side_texture}" + "end": "${end_texture}" + "side": "${side_texture}" # template: default:model/cube # arguments: # model: model_path @@ -44,7 +44,7 @@ templates#models#block: # south_texture: south_texture_path # west_texture: west_texture_path default:model/cube: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_column" textures: @@ -64,21 +64,21 @@ templates#models#2d: # texture: texture_path default:model/generated: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{texture}" + "layer0": "${texture}" # template: default:model/simplified_generated # arguments: # path: [model/texture]_path default:model/simplified_generated: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{path}" + "layer0": "${path}" # template: default:model/2_layer_generated # arguments: # model: model_path @@ -86,33 +86,33 @@ templates#models#2d: # layer1: texture_path default:model/2_layer_generated: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{layer0}" - "layer1": "{layer1}" + "layer0": "${layer0}" + "layer1": "${layer1}" # template: default:model/handheld # arguments: # model: model_path # texture: texture_path default:model/handheld: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/handheld" textures: - "layer0": "{texture}" + "layer0": "${texture}" # template: default:model/simplified_handheld # arguments: # path: [model/texture]_path default:model/simplified_handheld: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/handheld" textures: - "layer0": "{path}" + "layer0": "${path}" # template: default:model/elytra # arguments: # model: model_path @@ -123,17 +123,17 @@ templates#models#2d: type: "minecraft:condition" property: minecraft:broken on-false: - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: - path: "{broken_model}" + path: "${broken_model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{broken_texture}" + "layer0": "${broken_texture}" # template: default:model/simplified_elytra # arguments: # path: [model/texture]_path @@ -141,10 +141,10 @@ templates#models#2d: default:model/simplified_elytra: template: default:model/elytra arguments: - model: "{path}" - texture: "{path}" - broken_model: "{broken_path}" - broken_texture: "{broken_path}" + model: "${path}" + texture: "${path}" + broken_model: "${broken_path}" + broken_texture: "${broken_path}" # shield templates#models#shield: @@ -157,10 +157,10 @@ templates#models#shield: property: "minecraft:using_item" on-false: type: minecraft:model - path: "{model}" + path: "${model}" on-true: type: minecraft:model - path: "{block_model}" + path: "${block_model}" # fishing rods templates#models#fishing_rod: @@ -173,10 +173,10 @@ templates#models#fishing_rod: property: "minecraft:fishing_rod/cast" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" on-true: type: "minecraft:model" - path: "{cast_model}" + path: "${cast_model}" # template: default:model/fishing_rod_2d # arguments: # model: rod_model_path @@ -188,18 +188,18 @@ templates#models#fishing_rod: property: "minecraft:fishing_rod/cast" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/fishing_rod" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:model" - path: "{cast_model}" + path: "${cast_model}" generation: parent: "minecraft:item/fishing_rod" textures: - "layer0": "{cast_texture}" + "layer0": "${cast_texture}" # template: default:model/simplified_fishing_rod_2d # arguments: # path: rod_[model/texture]_path @@ -207,10 +207,10 @@ templates#models#fishing_rod: default:model/simplified_fishing_rod_2d: template: default:model/fishing_rod_2d arguments: - texture: "{path}" - model: "{path}" - cast_texture: "{cast_path}" - cast_model: "{cast_path}" + texture: "${path}" + model: "${path}" + cast_texture: "${cast_path}" + cast_model: "${cast_path}" # bows templates#models#bow: @@ -225,7 +225,7 @@ templates#models#bow: property: "minecraft:using_item" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" on-true: type: "minecraft:range_dispatch" property: "minecraft:use_duration" @@ -233,15 +233,15 @@ templates#models#bow: entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" threshold: 0.65 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" threshold: 0.9 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" # template: default:model/bow_2d # arguments: # model: bow_model_path @@ -257,11 +257,11 @@ templates#models#bow: property: "minecraft:using_item" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/bow" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:range_dispatch" property: "minecraft:use_duration" @@ -269,27 +269,27 @@ templates#models#bow: entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" generation: parent: "minecraft:item/bow_pulling_1" textures: - "layer0": "{pulling_1_texture}" + "layer0": "${pulling_1_texture}" threshold: 0.65 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" generation: parent: "minecraft:item/bow_pulling_2" textures: - "layer0": "{pulling_2_texture}" + "layer0": "${pulling_2_texture}" threshold: 0.9 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" generation: parent: "minecraft:item/bow_pulling_0" textures: - "layer0": "{pulling_0_texture}" + "layer0": "${pulling_0_texture}" # template: default:model/simplified_bow_2d # arguments: # path: bow_[model/texture]_path @@ -299,14 +299,14 @@ templates#models#bow: default:model/simplified_bow_2d: template: default:model/bow_2d arguments: - model: "{path}" - pulling_0_model: "{pulling_0_path}" - pulling_1_model: "{pulling_1_path}" - pulling_2_model: "{pulling_2_path}" - texture: "{path}" - pulling_0_texture: "{pulling_0_path}" - pulling_1_texture: "{pulling_1_path}" - pulling_2_texture: "{pulling_2_path}" + model: "${path}" + pulling_0_model: "${pulling_0_path}" + pulling_1_model: "${pulling_1_path}" + pulling_2_model: "${pulling_2_path}" + texture: "${path}" + pulling_0_texture: "${pulling_0_path}" + pulling_1_texture: "${pulling_1_path}" + pulling_2_texture: "${pulling_2_path}" # crossbows templates#models#crossbow: @@ -328,29 +328,29 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_model}" + path: "${arrow_model}" - when: rocket model: type: minecraft:model - path: "{firework_model}" + path: "${firework_model}" fallback: type: minecraft:model - path: "{model}" + path: "${model}" on-true: type: "minecraft:range_dispatch" property: "minecraft:crossbow/pull" entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" threshold: 0.58 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" threshold: 1.0 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" # template: default:model/crossbow_2d # arguments: # model: crossbow_model_path @@ -375,53 +375,53 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_model}" + path: "${arrow_model}" generation: parent: "minecraft:item/crossbow_arrow" textures: - "layer0": "{arrow_texture}" + "layer0": "${arrow_texture}" - when: rocket model: type: minecraft:model - path: "{firework_model}" + path: "${firework_model}" generation: parent: "minecraft:item/crossbow_firework" textures: - "layer0": "{firework_texture}" + "layer0": "${firework_texture}" fallback: type: minecraft:model - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/crossbow" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:range_dispatch" property: "minecraft:crossbow/pull" entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" generation: parent: "minecraft:item/crossbow_pulling_1" textures: - "layer0": "{pulling_1_texture}" + "layer0": "${pulling_1_texture}" threshold: 0.58 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" generation: parent: "minecraft:item/crossbow_pulling_2" textures: - "layer0": "{pulling_2_texture}" + "layer0": "${pulling_2_texture}" threshold: 1.0 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" generation: parent: "minecraft:item/crossbow_pulling_0" textures: - "layer0": "{pulling_0_texture}" + "layer0": "${pulling_0_texture}" # template: default:model/simplified_crossbow_2d # arguments: # path: crossbow_[model/texture]_path @@ -433,28 +433,28 @@ templates#models#crossbow: default:model/simplified_crossbow_2d: template: default:model/crossbow_2d arguments: - model: "{path}" - texture: "{path}" - arrow_model: "{arrow_path}" - arrow_texture: "{arrow_path}" - firework_model: "{firework_path}" - firework_texture: "{firework_path}" - pulling_0_model: "{pulling_0_path}" - pulling_0_texture: "{pulling_0_path}" - pulling_1_model: "{pulling_1_path}" - pulling_1_texture: "{pulling_1_path}" - pulling_2_model: "{pulling_2_path}" - pulling_2_texture: "{pulling_2_path}" + model: "${path}" + texture: "${path}" + arrow_model: "${arrow_path}" + arrow_texture: "${arrow_path}" + firework_model: "${firework_path}" + firework_texture: "${firework_path}" + pulling_0_model: "${pulling_0_path}" + pulling_0_texture: "${pulling_0_path}" + pulling_1_model: "${pulling_1_path}" + pulling_1_texture: "${pulling_1_path}" + pulling_2_model: "${pulling_2_path}" + pulling_2_texture: "${pulling_2_path}" # sounds templates#settings#sounds: default:sound/block_template: sounds: - break: "minecraft:block.{block_type}.break" - step: "minecraft:block.{block_type}.step" - place: "minecraft:block.{block_type}.place" - hit: "minecraft:block.{block_type}.hit" - fall: "minecraft:block.{block_type}.fall" + break: "minecraft:block.${block_type}.break" + step: "minecraft:block.${block_type}.step" + place: "minecraft:block.${block_type}.place" + hit: "minecraft:block.${block_type}.hit" + fall: "minecraft:block.${block_type}.fall" default:sound/crop: sounds: break: "minecraft:block.crop.break" @@ -614,7 +614,7 @@ templates#settings#break_level: # block settings templates#settings#blocks: default:settings/middle_click_pick_itself: - item: "{__NAMESPACE__}:{__ID__}" + item: "${__NAMESPACE__}:${__ID__}" default:settings/solid_1x1x1: is-suffocating: true replaceable: false @@ -696,7 +696,7 @@ templates#settings#blocks: default:settings/ore: template: - "default:sound/stone" - - "default:pickaxe_power/level_{break_power}" + - "default:pickaxe_power/level_${break_power}" overrides: hardness: 3.0 resistance: 3.0 @@ -712,7 +712,7 @@ templates#settings#blocks: default:settings/deepslate_ore: template: - "default:sound/deepslate" - - "default:pickaxe_power/level_{break_power}" + - "default:pickaxe_power/level_${break_power}" overrides: hardness: 4.5 resistance: 3.0 @@ -735,45 +735,45 @@ templates#block_states: default: y appearances: axisY: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: - path: "{model_vertical_path}" + path: "${model_vertical_path}" generation: parent: "minecraft:block/cube_column" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" axisX: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: x: 90 y: 90 - path: "{model_horizontal_path}" + path: "${model_horizontal_path}" generation: parent: "minecraft:block/cube_column_horizontal" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" axisZ: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: x: 90 - path: "{model_horizontal_path}" + path: "${model_horizontal_path}" generation: parent: "minecraft:block/cube_column_horizontal" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" variants: axis=x: appearance: axisX - id: "{internal_id}" + id: "${internal_id}" axis=y: appearance: axisY - id: "{internal_id}" + id: "${internal_id}" axis=z: appearance: axisZ - id: "{internal_id}" + id: "${internal_id}" default:block_state/leaves: properties: waterlogged: @@ -788,107 +788,107 @@ templates#block_states: range: 1~7 appearances: default: - state: "{default_state}" + state: "${default_state}" model: - path: "{model_path}" + path: "${model_path}" generation: parent: "minecraft:block/leaves" textures: - "all": "{texture_path}" + "all": "${texture_path}" waterlogged: - state: "{waterlogged_state}" + state: "${waterlogged_state}" model: - path: "{model_path}" + path: "${model_path}" variants: distance=1,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=2,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=3,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=4,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=5,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=6,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=7,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" settings: is-randomly-ticking: true distance=1,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=2,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=3,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=4,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=5,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=6,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=7,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=1,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false @@ -896,49 +896,49 @@ templates#block_states: fluid-state: water distance=1,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false @@ -951,9 +951,9 @@ templates#recipes: category: building group: planks ingredients: - A: "#default:{wood_type}_logs" + A: "#default:${wood_type}_logs" result: - id: "default:{wood_type}_planks" + id: "default:${wood_type}_planks" count: 4 default:recipe/log_2_wood: type: shaped @@ -963,29 +963,29 @@ templates#recipes: - "AA" - "AA" ingredients: - A: "default:{wood_type}_log" + A: "default:${wood_type}_log" result: - id: "default:{wood_type}_wood" + id: "default:${wood_type}_wood" count: 3 default:recipe/smelting_ore: type: smelting - experience: "{exp}" + experience: "${exp}" category: misc group: topaz time: 200 - ingredient: "{ingredient}" + ingredient: "${ingredient}" result: - id: "{result}" + id: "${result}" count: 1 default:recipe/blasting_ore: type: blasting - experience: "{exp}" + experience: "${exp}" category: misc group: topaz time: 100 - ingredient: "{ingredient}" + ingredient: "${ingredient}" result: - id: "{result}" + id: "${result}" count: 1 # loot tables @@ -1001,7 +1001,7 @@ templates#loot_tables: - type: survives_explosion entries: - type: item - item: "{__NAMESPACE__}:{__ID__}" + item: "${__NAMESPACE__}:${__ID__}" # drop one item @@ -1015,7 +1015,7 @@ templates#loot_tables: - type: survives_explosion entries: - type: item - item: "{item}" + item: "${item}" # drop the original furniture item or a fallback item @@ -1027,7 +1027,7 @@ templates#loot_tables: - rolls: 1 entries: - type: furniture_item - item: "{item}" + item: "${item}" # drop with silk touch @@ -1042,7 +1042,7 @@ templates#loot_tables: predicate: minecraft:silk_touch>=1 entries: - type: item - item: "{item}" + item: "${item}" # crop drops @@ -1058,21 +1058,21 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{crop_item}" + item: "${crop_item}" conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" - type: item - item: "{crop_seed}" + item: "${crop_seed}" - rolls: 1 conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" entries: - type: item - item: "{crop_seed}" + item: "${crop_seed}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1090,15 +1090,15 @@ templates#loot_tables: - rolls: 1 entries: - type: item - item: "{crop_item}" + item: "${crop_item}" - rolls: 1 conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" entries: - type: item - item: "{crop_item}" + item: "${crop_item}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1122,12 +1122,12 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{ore_block}" + item: "${ore_block}" conditions: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{ore_drop}" + item: "${ore_drop}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1137,8 +1137,8 @@ templates#loot_tables: - type: drop_exp count: type: uniform - min: "{min_exp}" - max: "{max_exp}" + min: "${min_exp:-2}" + max: "${max_exp:-4}" # template: default:loot_table/ore_no_exp # arguments: @@ -1151,12 +1151,12 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{ore_block}" + item: "${ore_block}" conditions: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{ore_drop}" + item: "${ore_drop}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1177,7 +1177,7 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{leaves}" + item: "${leaves}" conditions: - type: any_of terms: @@ -1186,7 +1186,7 @@ templates#loot_tables: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{sapling}" + item: "${sapling}" conditions: - type: survives_explosion - type: table_bonus diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 9c32bd009..f01daf055 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -69,21 +69,21 @@ images: templates: internal:icon/2d: material: arrow - custom-model-data: "{model_data}" + custom-model-data: "${model_data}" data: - item-name: "{name}" - lore: "{lore}" + item-name: "${name}" + lore: "${lore}" model: template: "internal:model/simplified_generated" arguments: - path: "minecraft:item/custom/gui/{texture}" + path: "minecraft:item/custom/gui/${texture}" internal:model/simplified_generated: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{path}" + "layer0": "${path}" items: internal:next_page_0: 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 bd621ea79..e412ea280 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 @@ -37,6 +37,7 @@ public class ItemSettings { Helmet helmet = null; FoodData foodData = null; Key consumeReplacement = null; + Key craftRemainder = null; private ItemSettings() {} @@ -74,6 +75,7 @@ public class ItemSettings { newSettings.helmet = settings.helmet; newSettings.foodData = settings.foodData; newSettings.consumeReplacement = settings.consumeReplacement; + newSettings.craftRemainder = settings.craftRemainder; return newSettings; } @@ -240,7 +242,10 @@ 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("consume-replacement", (value -> settings -> { + if (value == null) settings.consumeReplacement(null); + else 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())); @@ -293,6 +298,9 @@ public class ItemSettings { ); return settings -> settings.foodData(data); })); +// registerFactory("craft-remainder", (value -> { +// +// })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java index 476e407c6..0f7e64dd4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java @@ -66,16 +66,17 @@ public interface TemplateManager extends Manageable { private final String rawText; private final Object defaultValue; - public Placeholder(String placeholder) { - this.rawText = "{" + placeholder + "}"; - int first = placeholder.indexOf(':'); - if (first == -1) { - this.placeholder = placeholder; + public Placeholder(String placeholderContent) { + this.rawText = "${" + placeholderContent + "}"; + int separatorIndex = placeholderContent.indexOf(":-"); + if (separatorIndex == -1) { + this.placeholder = placeholderContent; this.defaultValue = this.rawText; } else { - this.placeholder = placeholder.substring(0, first); + this.placeholder = placeholderContent.substring(0, separatorIndex); + String defaultValueString = placeholderContent.substring(separatorIndex + 2); try { - this.defaultValue = CraftEngine.instance().platform().nbt2Java(placeholder.substring(first + 1)); + this.defaultValue = CraftEngine.instance().platform().nbt2Java(defaultValueString); } catch (LocalizedResourceConfigException e) { e.appendTailArgument(this.placeholder); throw e; @@ -220,42 +221,33 @@ public interface TemplateManager extends Manageable { while (i < n) { char c = input.charAt(i); - // --- 1. 处理转义字符 --- - if (c == '\\') { - // 只在'\'后面是'{'或'}'时才作为转义处理 - if (i + 1 < n && (input.charAt(i + 1) == '{' || input.charAt(i + 1) == '}')) { - currentLiteral.append(input.charAt(i + 1)); // 添加花括号 - i += 2; // 跳过'\'和花括号 - } else { - // 对于所有其他情况 (如 \\, \n), 将'\'视为普通字符 - currentLiteral.append(c); - i++; - } - continue; - } + // --- 1. 优先检测占位符触发器 --- + if (c == '$' && i + 1 < n && input.charAt(i + 1) == '{') { - // --- 2. 处理占位符 {key} --- - if (c == '{') { - // 如果在占位符之前有普通文本,先提交它 + // a. 提交之前的普通文本 if (!currentLiteral.isEmpty()) { arguments.add(Literal.literal(currentLiteral.toString())); - currentLiteral.setLength(0); // 清空 + currentLiteral.setLength(0); } - // 开始解析占位符内部 + // b. 解析占位符内部,此处的逻辑拥有自己的转义规则 + int contentStartIndex = i + 2; StringBuilder keyBuilder = new StringBuilder(); int depth = 1; - int j = i + 1; + int j = contentStartIndex; boolean foundMatch = false; while (j < n) { char innerChar = input.charAt(j); - if (innerChar == '\\') { // 处理占位符内部的转义 + + // --- 占位符内部的转义逻辑 --- + if (innerChar == '\\') { if (j + 1 < n && (input.charAt(j + 1) == '{' || input.charAt(j + 1) == '}')) { keyBuilder.append(input.charAt(j + 1)); j += 2; } else { - keyBuilder.append(innerChar); // 将'\'视为普通字符 + // 在占位符内部,一个无法识别的转义\依旧被当作普通\处理 + keyBuilder.append(innerChar); j++; } } else if (innerChar == '{') { @@ -266,11 +258,11 @@ public interface TemplateManager extends Manageable { depth--; if (depth == 0) { // 找到匹配的闭合括号 arguments.add(Placeholder.placeholder(keyBuilder.toString())); - i = j + 1; // 将主循环的索引跳到占位符之后 + i = j + 1; foundMatch = true; break; } - keyBuilder.append(innerChar); // 嵌套的 '}' + keyBuilder.append(innerChar); j++; } else { keyBuilder.append(innerChar); @@ -279,27 +271,31 @@ public interface TemplateManager extends Manageable { } if (foundMatch) { - continue; // 成功解析占位符,继续主循环 + continue; } else { - // 没有找到匹配的 '}',将起始的 '{' 视为普通文本 + // 未找到闭合括号,将 '$' 视为普通字符 currentLiteral.append(c); i++; } - } else { - // --- 3. 处理普通字符 --- + } + // --- 2. 其次,只处理对触发器'$'的转义 --- + else if (c == '\\' && i + 1 < n && input.charAt(i + 1) == '$') { + currentLiteral.append('$'); // 直接添加 '$' + i += 2; // 跳过 '\' 和 '$' + } + // --- 3. 处理所有其他字符(包括独立的'\'和'{')为普通文本 --- + else { currentLiteral.append(c); i++; } } - // 添加循环结束后剩余的任何普通文本 if (!currentLiteral.isEmpty()) { arguments.add(Literal.literal(currentLiteral.toString())); } - // 根据解析出的参数数量返回最终结果 return switch (arguments.size()) { - case 0 -> Literal.literal(""); // 处理 input = "{}" 等情况 + case 0 -> Literal.literal(""); case 1 -> arguments.getFirst(); case 2 -> new Complex2(input, arguments.get(0), arguments.get(1)); default -> new Complex(input, arguments); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java index 83e0853a5..910678475 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java @@ -33,7 +33,7 @@ public abstract class AbstractCommonContext implements Context { public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new I18NTag(this), new NamedArgumentTag(this), - new PlaceholderTag(null), new ExpressionTag(this), new GlobalVariableTag(this)}; + new PlaceholderTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } return this.tagResolvers; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java index e71cf975b..72667d538 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java @@ -57,7 +57,7 @@ public class PlayerOptionalContext extends AbstractChainParameterContext impleme @NotNull public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { - this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this), new I18NTag(this), new NamedArgumentTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } return this.tagResolvers; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java index cc4f2d761..affc6cd72 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java @@ -53,19 +53,15 @@ public class ViewerContext implements RelationalContext { @Override public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { - Player optionalOwner = null; - if (this.owner instanceof PlayerOptionalContext context) { - optionalOwner = context.player(); - } - if (optionalOwner != null && this.viewer.player != null) { - this.tagResolvers = new TagResolver[]{new RelationalPlaceholderTag(optionalOwner, this.viewer.player), + if (this.owner instanceof PlayerOptionalContext context && context.player != null && this.viewer.player != null) { + this.tagResolvers = new TagResolver[]{new RelationalPlaceholderTag(context.player, this.viewer.player, this), ShiftTag.INSTANCE, ImageTag.INSTANCE, - new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + new PlaceholderTag(this.owner), new ViewerPlaceholderTag(this.viewer), new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), new I18NTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } else { this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, - new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + new PlaceholderTag(this.owner), new ViewerPlaceholderTag(this.viewer), new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), new I18NTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java index c326b284b..019d915e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java @@ -5,17 +5,17 @@ import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class PlaceholderTag implements TagResolver { - private final Player player; + private final net.momirealms.craftengine.core.plugin.context.Context context; - public PlaceholderTag(@Nullable Player player) { - this.player = player; + public PlaceholderTag(@NotNull net.momirealms.craftengine.core.plugin.context.Context context) { + this.context = context; } @Override @@ -23,8 +23,10 @@ public class PlaceholderTag implements TagResolver { if (!this.has(name) || !CraftEngine.instance().compatibilityManager().hasPlaceholderAPI()) { return null; } - String placeholder = "%" + arguments.popOr("No argument placeholder provided") + "%"; - String parsed = CraftEngine.instance().compatibilityManager().parse(player, placeholder); + String rawArgument = arguments.popOr("No argument relational placeholder provided").toString(); + if (rawArgument.contains("<")) rawArgument = AdventureHelper.resolvePlainStringTags(rawArgument, this.context.tagResolvers()); + String placeholder = "%" + rawArgument + "%"; + String parsed = this.context instanceof PlayerOptionalContext playerOptionalContext ? CraftEngine.instance().compatibilityManager().parse(playerOptionalContext.player(), placeholder) : CraftEngine.instance().compatibilityManager().parse(null, placeholder); if (parsed.equals(placeholder)) { parsed = arguments.popOr("No default papi value provided").toString(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java index 07f175b6d..4815ec310 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java @@ -7,6 +7,8 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.RelationalContext; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,10 +16,12 @@ import org.jetbrains.annotations.Nullable; public class RelationalPlaceholderTag implements TagResolver { private final Player player1; private final Player player2; + private final RelationalContext context; - public RelationalPlaceholderTag(@NotNull Player player1, @NotNull Player player2) { + public RelationalPlaceholderTag(@NotNull Player player1, @NotNull Player player2, RelationalContext context) { this.player1 = player1; this.player2 = player2; + this.context = context; } @Override @@ -25,8 +29,10 @@ public class RelationalPlaceholderTag implements TagResolver { if (!this.has(name) || !CraftEngine.instance().compatibilityManager().hasPlaceholderAPI()) { return null; } - String placeholder = "%" + arguments.popOr("No argument placeholder provided") + "%"; - String parsed = CraftEngine.instance().compatibilityManager().parse(player1, player2, placeholder); + String rawArgument = arguments.popOr("No argument placeholder provided").toString(); + if (rawArgument.contains("<")) rawArgument = AdventureHelper.resolvePlainStringTags(rawArgument, this.context.tagResolvers()); + String placeholder = "%" + rawArgument + "%"; + String parsed = CraftEngine.instance().compatibilityManager().parse(this.player1, this.player2, placeholder); if (parsed.equals(placeholder)) { parsed = arguments.popOr("No default papi value provided").toString(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java index 397a891ff..383c4ec12 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java @@ -1,12 +1,11 @@ package net.momirealms.craftengine.core.plugin.text.minimessage; -import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Context; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ViewerPlaceholderTag extends PlaceholderTag { - public ViewerPlaceholderTag(@Nullable Player player) { + public ViewerPlaceholderTag(@NotNull Context player) { super(player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index c404f15a8..3ed1f6048 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -316,6 +316,11 @@ public class AdventureHelper { return true; } + public static String resolvePlainStringTags(String raw, TagResolver... resolvers) { + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(raw, resolvers); + return AdventureHelper.plainTextContent(resultComponent); + } + public static Component replaceText(Component text, Map replacements) { String patternString = replacements.keySet().stream() .map(Pattern::quote) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index 1aeb6d3f9..572c8b5ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -104,7 +104,7 @@ public class MiscUtils { public static void deepMergeMaps(Map baseMap, Map mapToMerge) { for (Map.Entry entry : mapToMerge.entrySet()) { String key = entry.getKey(); - if (!key.isEmpty() && key.charAt(0) == '$') { + if (key.length() > 2 && key.charAt(0) == '$' && key.charAt(1) == '$') { Object value = entry.getValue(); baseMap.put(key.substring(1), value); } else { diff --git a/gradle.properties b/gradle.properties index 6e05db11f..c65d6830a 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.5 +project_version=0.0.56.6 config_version=36 lang_version=15 project_group=net.momirealms @@ -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.67.3 +nms_helper_version=0.67.7 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 2c06db83afdcb4aa467360d45b12af31c0da5502 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 11 Jun 2025 20:28:09 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AE=80=E6=98=93?= =?UTF-8?q?=E7=9A=84=E8=BF=81=E7=A7=BB=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/BukkitCommandManager.java | 1 + .../feature/DebugMigrateTemplatesCommand.java | 60 +++++++++++++++++++ common-files/src/main/resources/commands.yml | 7 +++ .../craftengine/core/item/ItemSettings.java | 12 +++- gradle.properties | 4 +- 5 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index ccc824bd9..87288628b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -48,6 +48,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugSpawnFurnitureCommand(this, plugin), new DebugTargetBlockCommand(this, plugin), new DebugIsSectionInjectedCommand(this, plugin), + new DebugMigrateTemplatesCommand(this, plugin), new DebugEntityId2UUIDCommand(this, plugin), new TotemAnimationCommand(this, plugin), new EnableResourceCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java new file mode 100644 index 000000000..227b0f19f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.FileUtils; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.Command; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DebugMigrateTemplatesCommand extends BukkitCommandFeature { + private static final Pattern PATTERN = Pattern.compile("(? commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .handler(context -> { + for (Pack pack : BukkitCraftEngine.instance().packManager().loadedPacks()) { + for (Path file : FileUtils.getYmlConfigsDeeply(pack.configurationFolder())) { + try { + Files.writeString(file, replacePlaceholders(Files.readString(file))); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + context.sender().sendMessage("Done"); + }); + } + + @Override + public String getFeatureID() { + return "debug_migrate_templates"; + } + + private static String replacePlaceholders(String input) { + if (input == null) { + return null; + } + Matcher matcher = PATTERN.matcher(input); + StringBuilder sb = new StringBuilder(); + while (matcher.find()) { + // 将 {xxx} 替换为 ${xxx} + matcher.appendReplacement(sb, "\\${" + matcher.group(1) + "}"); + } + matcher.appendTail(sb); + return sb.toString(); + } +} \ No newline at end of file diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index d7b499210..17aa9c83e 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -189,6 +189,13 @@ debug_entity_id_to_uuid: - /craftengine debug entity-id-to-uuid - /ce debug entity-id-to-uuid +debug_migrate_templates: + enable: true + permission: ce.command.debug.migrate_templates + usage: + - /craftengine debug migrate-templates + - /ce debug migrate-templates + debug_test: enable: true permission: ce.command.debug.test 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 e412ea280..3398b7e9f 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 @@ -153,6 +153,11 @@ public class ItemSettings { return this; } + public ItemSettings craftRemainder(Key key) { + this.craftRemainder = key; + return this; + } + public ItemSettings canRepair(boolean canRepair) { this.canRepair = canRepair; return this; @@ -246,6 +251,10 @@ public class ItemSettings { if (value == null) settings.consumeReplacement(null); else settings.consumeReplacement(Key.of(value.toString())); })); + registerFactory("craft-remainder", (value -> settings -> { + if (value == null) settings.craftRemainder(null); + else settings.craftRemainder(Key.of(value.toString())); + })); registerFactory("tags", (value -> { List tags = MiscUtils.getAsStringList(value); return settings -> settings.tags(tags.stream().map(Key::of).collect(Collectors.toSet())); @@ -298,9 +307,6 @@ public class ItemSettings { ); return settings -> settings.foodData(data); })); -// registerFactory("craft-remainder", (value -> { -// -// })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { diff --git a/gradle.properties b/gradle.properties index c65d6830a..1395597ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,8 +3,8 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.56.6 -config_version=36 -lang_version=15 +config_version=37 +lang_version=16 project_group=net.momirealms latest_supported_version=1.21.5 From 2187362984e322879e551c098e5db29d69bc61c7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 11 Jun 2025 21:31:33 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E7=89=A9=E5=93=81=E8=BF=94=E8=BF=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/RecipeEventListener.java | 43 +++++++++++++++++++ .../craftengine/core/item/ItemSettings.java | 7 ++- gradle.properties | 2 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index b1ab779fc..e13f6b558 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -33,6 +33,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Campfire; import org.bukkit.block.Furnace; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -790,6 +791,48 @@ public class RecipeEventListener implements Listener { return new Pair<>(first, second); } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onCraft(CraftItemEvent event) { + org.bukkit.inventory.Recipe recipe = event.getRecipe(); + if (!(recipe instanceof ShapelessRecipe) && !(recipe instanceof ShapedRecipe)) return; + HumanEntity humanEntity = event.getWhoClicked(); + if (!(humanEntity instanceof Player player)) return; + CraftingInventory inventory = event.getInventory(); + ItemStack result = inventory.getResult(); + if (result == null) return; + ItemStack[] usedItems = inventory.getMatrix(); + ItemStack[] replacements = new ItemStack[usedItems.length]; + boolean hasReplacement = false; + for (int i = 0; i < usedItems.length; i++) { + ItemStack usedItem = usedItems[i]; + if (ItemUtils.isEmpty(usedItem)) continue; + if (usedItem.getAmount() != 1) continue; + Item wrapped = BukkitItemManager.instance().wrap(usedItem); + if (wrapped == null) continue; + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + Key remainingItem = customItem.settings().craftRemainder(); + if (remainingItem != null) { + replacements[i] = BukkitItemManager.instance().buildItemStack(remainingItem, this.plugin.adapt(player)); + hasReplacement = true; + } + } + } + if (!hasReplacement) return; + Runnable delayedTask = () -> { + for (int i = 0; i < replacements.length; i++) { + if (replacements[i] == null) continue; + inventory.setItem(i + 1, replacements[i]); + } + }; + if (VersionHelper.isFolia()) { + player.getScheduler().run(this.plugin.javaPlugin(), (t) -> delayedTask.run(), () -> {}); + } else { + this.plugin.scheduler().sync().runDelayed(delayedTask); + } + } + @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { if (!Config.enableRecipeSystem()) return; 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 3398b7e9f..5208d5576 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 @@ -133,6 +133,11 @@ public class ItemSettings { return consumeReplacement; } + @Nullable + public Key craftRemainder() { + return craftRemainder; + } + @Nullable public Helmet helmet() { return helmet; @@ -251,7 +256,7 @@ public class ItemSettings { if (value == null) settings.consumeReplacement(null); else settings.consumeReplacement(Key.of(value.toString())); })); - registerFactory("craft-remainder", (value -> settings -> { + registerFactory("craft-remaining-item", (value -> settings -> { if (value == null) settings.craftRemainder(null); else settings.craftRemainder(Key.of(value.toString())); })); diff --git a/gradle.properties b/gradle.properties index 1395597ac..796031ea2 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.6 +project_version=0.0.56.7 config_version=37 lang_version=16 project_group=net.momirealms From a56d94a80342493d3834baf26f7fcff146f9e702 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 12 Jun 2025 02:09:06 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=89=93=E7=81=AB?= =?UTF-8?q?=E7=9F=B3=E9=9F=B3=E6=95=88=E8=A1=A5=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 2 + .../item/behavior/BukkitItemBehaviors.java | 2 + .../behavior/FlintAndSteelItemBehavior.java | 120 ++++++++++++++++++ .../item/listener/ItemEventListener.java | 1 + .../reflection/minecraft/CoreReflections.java | 16 +++ .../plugin/user/BukkitServerPlayer.java | 5 +- .../bukkit/util/BlockStateUtils.java | 15 +++ .../default/configuration/blocks.yml | 2 +- .../core/entity/player/Player.java | 7 +- .../craftengine/core/item/ItemKeys.java | 1 + 10 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index d909239f3..627e1071a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item; import com.saicone.rtag.item.ItemTagStream; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener; @@ -43,6 +44,7 @@ public class BukkitItemManager extends AbstractItemManager { static { registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS); registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET); + registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL); } private static BukkitItemManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index f8081572b..a30c6bb03 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -10,6 +10,7 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item"); public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item"); + public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item"); public static void init() { register(EMPTY, EmptyItemBehavior.FACTORY); @@ -18,5 +19,6 @@ public class BukkitItemBehaviors extends ItemBehaviors { register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY); register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY); register(BUCKET_ITEM, BucketItemBehavior.FACTORY); + register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java new file mode 100644 index 000000000..66b918a98 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -0,0 +1,120 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.InteractUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.sound.SoundSource; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.nio.file.Path; +import java.util.Map; + +public class FlintAndSteelItemBehavior extends ItemBehavior { + public static final FlintAndSteelItemBehavior INSTANCE = new FlintAndSteelItemBehavior(); + public static final Factory FACTORY = new Factory(); + private static final Key FLINT_SOUND = Key.of("item.flintandsteel.use"); + + @SuppressWarnings("unchecked") + @Override + public InteractionResult useOnBlock(UseOnContext context) { + BlockPos clickedPos = context.getClickedPos(); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos); + Block block = clicked.block(); + BlockPos firePos = clickedPos.relative(context.getClickedFace()); + Direction direction = context.getHorizontalDirection(); + + // 最基础的判断能不能着火,不能着火都是扯蛋 + try { + if (!(boolean) CoreReflections.method$BaseFireBlock$canBePlacedAt.invoke(null, context.getLevel().serverWorld(), LocationUtils.toBlockPos(firePos), DirectionUtils.toNMSDirection(direction))) { + return InteractionResult.PASS; + } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to run BaseFireBlock$canBePlacedAt", e); + return InteractionResult.PASS; + } + + net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer(); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); + if (state == null || state.isEmpty()) { + return InteractionResult.PASS; + } else { + // 玩家交互目标是自定义方块 + if (context.getClickedFace() == Direction.UP) { + // 客户端层面必须可交互 + if (!InteractUtils.isInteractable((Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item) context.getItem())) { + return InteractionResult.PASS; + } + // 且没有shift + if (!player.isSecondaryUseActive()) { + player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + BlockData vanillaBlockState = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()); + // 原版状态可燃烧,则跳过 + if (BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(vanillaBlockState))) { + return InteractionResult.PASS; + } + + // 客户端一定觉得这个东西不可燃烧 + BlockPos belowFirePos = firePos.relative(Direction.DOWN); + BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); + boolean belowCanBurn; + try { + Block belowBlock = belowFireBlock.block(); + belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || + (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + + // 客户端觉得这玩意可交互,就会忽略声音 + if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { + // 如果按住了shift,则不会挥手,补发 + if (player.isSecondaryUseActive()) { + // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } else { + player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } + } + } + return InteractionResult.PASS; + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} 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 0bec09f6b..e246395ee 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 @@ -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.block.BlockIgniteEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index e8cf86bb1..b5dbea9c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.mojang.serialization.DynamicOps; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; @@ -3296,4 +3297,19 @@ public final class CoreReflections { throw new ReflectionInitException("Failed to initialize reflection", e); } } + + public static final Class clazz$BaseFireBlock = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.block.BlockFireAbstract", + "world.level.block.BaseFireBlock" + ) + ); + + public static final Method method$BaseFireBlock$canBePlacedAt = requireNonNull( + ReflectionUtils.getStaticMethod(clazz$BaseFireBlock, boolean.class, clazz$Level, clazz$BlockPos, clazz$Direction) + ); + + public static final Field field$FireBlock$igniteOdds = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0) + ); } 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 436b5b6a9..16c8c2bfb 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 @@ -30,6 +30,7 @@ import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -283,8 +284,8 @@ public class BukkitServerPlayer extends Player { } @Override - public void playSound(Key sound, float volume, float pitch) { - platformPlayer().playSound(platformPlayer(), sound.toString(), SoundCategory.MASTER, volume, pitch); + public void playSound(Key sound, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index c2eb45f8c..c0079d0e9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +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.NetworkReflections; import net.momirealms.craftengine.core.block.*; @@ -22,18 +24,26 @@ import org.jetbrains.annotations.Nullable; import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; import java.util.Optional; public class BlockStateUtils { public static final IdentityHashMap CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>(); private static int vanillaStateSize; private static boolean hasInit; + public static Map IGNITE_ODDS; + @SuppressWarnings("unchecked") public static void init(int size) { if (hasInit) { throw new IllegalStateException("BlockStateUtils has already been initialized"); } vanillaStateSize = size; + try { + IGNITE_ODDS = (Map) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e); + } hasInit = true; } @@ -248,4 +258,9 @@ public class BlockStateUtils { public static int vanillaStateSize() { return vanillaStateSize; } + + public static boolean isBurnable(Object state) { + Object blockOwner = getBlockOwner(state); + return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0; + } } diff --git a/common-files/src/main/resources/resources/default/configuration/blocks.yml b/common-files/src/main/resources/resources/default/configuration/blocks.yml index 4c1fbbc7d..3fa3526c9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks.yml @@ -167,7 +167,7 @@ items#misc: template: "default:loot_table/self" settings: template: - - default:sound/sand + - default:sound/stone - default:pickaxe_power/level_1 - default:settings/solid_1x1x1 overrides: diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 5e0309c97..302d40d78 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; import org.jetbrains.annotations.Nullable; @@ -81,7 +82,11 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { playSound(sound, 1f, 1f); } - public abstract void playSound(Key sound, float volume, float pitch); + public void playSound(Key sound, float volume, float pitch) { + playSound(sound, SoundSource.MASTER, volume, pitch); + } + + public abstract void playSound(Key sound, SoundSource source, float volume, float pitch); public abstract void giveItem(Item item); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index d8419d2ea..a90a44e69 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.util.Key; public class ItemKeys { public static final Key AIR = Key.of("minecraft:air"); + public static final Key FLINT_AND_STEEL = Key.of("minecraft:flint_and_steel"); public static final Key STONE = Key.of("minecraft:stone"); public static final Key TRIDENT = Key.of("minecraft:trident"); public static final Key SHIELD = Key.of("minecraft:shield"); From f9adaeff007b3566b51c7b8551d7b9c7532fc9aa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 12 Jun 2025 02:32:23 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=AE=8C=E7=BE=8E=E7=82=B9=E7=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/FlintAndSteelItemBehavior.java | 132 +++++++++++------- .../plugin/user/BukkitServerPlayer.java | 6 + .../core/entity/player/Player.java | 3 + 3 files changed, 94 insertions(+), 47 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index 66b918a98..03b3b822a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -21,6 +21,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -48,65 +49,102 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { return InteractionResult.PASS; } } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to run BaseFireBlock$canBePlacedAt", e); + CraftEngine.instance().logger().warn("Failed to call BaseFireBlock$canBePlacedAt", e); + return InteractionResult.PASS; + } + + // 判断点击的方块是否可燃 + BlockData clickedBlockData = block.getBlockData(); + Object clickedBlockState = BlockStateUtils.blockDataToBlockState(clickedBlockData); + boolean isClickedBlockBurnable; + try { + isClickedBlockBurnable = BlockStateUtils.isBurnable(clickedBlockState) || + (context.getClickedFace() == Direction.UP && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + clickedBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); return InteractionResult.PASS; } net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer(); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); - if (state == null || state.isEmpty()) { - return InteractionResult.PASS; - } else { - // 玩家交互目标是自定义方块 - if (context.getClickedFace() == Direction.UP) { - // 客户端层面必须可交互 - if (!InteractUtils.isInteractable((Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item) context.getItem())) { - return InteractionResult.PASS; - } - // 且没有shift - if (!player.isSecondaryUseActive()) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - } + // 点击对象直接可燃,则忽略 + if (isClickedBlockBurnable) { + int stateId = BlockStateUtils.blockStateToId(clickedBlockState); + if (BlockStateUtils.isVanillaBlock(stateId)) { + return InteractionResult.PASS; } else { - BlockData vanillaBlockState = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()); - // 原版状态可燃烧,则跳过 - if (BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(vanillaBlockState))) { + // 点击对象为自定义方块 + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + // 原版外观也可燃 + if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) { return InteractionResult.PASS; } - - // 客户端一定觉得这个东西不可燃烧 - BlockPos belowFirePos = firePos.relative(Direction.DOWN); - BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); - boolean belowCanBurn; - try { - Block belowBlock = belowFireBlock.block(); - belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || - (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( - BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); - return InteractionResult.PASS; - } - - // 客户端觉得这玩意可交互,就会忽略声音 - if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { - // 如果按住了shift,则不会挥手,补发 - if (player.isSecondaryUseActive()) { - // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 - if (!belowCanBurn) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - player.swingHand(context.getHand()); - } - } else { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()); + // 点击的是方块上面,则只需要判断shift和可交互 + if (context.getClickedFace() == Direction.UP) { + // 客户端层面必须可交互 + if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, + context.getHitResult(), (Item) context.getItem())) { + return InteractionResult.PASS; + } + // 且没有shift + if (!player.isSecondaryUseActive()) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); } } else { - if (!belowCanBurn) { - player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); - player.swingHand(context.getHand()); + // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 + BlockPos belowFirePos = firePos.relative(Direction.DOWN); + BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); + boolean belowCanBurn; + try { + Block belowBlock = belowFireBlock.block(); + belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || + (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + + // 客户端觉得这玩意可交互,就会忽略声音 + if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { + // 如果按住了shift,则代表尝试对侧面方块点火 + if (player.isSecondaryUseActive()) { + // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } else { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + // 如果底部方块不可燃烧才补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } } } } + } else { + // 如果点击的方块不可燃烧,但是服务端却认为可以放置火源,则可燃烧的方块一定位于火源的六个方向之一。 + Direction relativeDirection = direction.opposite(); + for (Direction dir : Direction.values()) { + if (dir == relativeDirection) continue; + BlockPos relPos = firePos.relative(dir); + BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos); + BlockData nearbyBlockData = nearByBlock.block().getBlockData(); + Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData); + int stateID = BlockStateUtils.blockStateToId(nearbyBlockState); + if (BlockStateUtils.isVanillaBlock(stateID)) { + if (BlockStateUtils.isBurnable(nearbyBlockState)) { + return InteractionResult.PASS; + } + } + } + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); } return InteractionResult.PASS; } 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 16c8c2bfb..8adcef88f 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 @@ -35,6 +35,7 @@ import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; import org.bukkit.*; @@ -288,6 +289,11 @@ public class BukkitServerPlayer extends Player { platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } + @Override + public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); + } + @Override public void giveItem(Item item) { PlayerUtils.giveItem(platformPlayer(), (ItemStack) item.getItem(), item.count()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 302d40d78..75b10c4f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -88,6 +89,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void playSound(Key sound, SoundSource source, float volume, float pitch); + public abstract void playSound(Key sound, BlockPos pos, SoundSource source, float volume, float pitch); + public abstract void giveItem(Item item); public abstract void closeInventory(); From 8b7383762ae06aceb3b872e1b2e1cebbb3656b34 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 12 Jun 2025 02:45:05 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=88=9A=E6=89=8D=E7=9A=84=E4=B8=8D?= =?UTF-8?q?=E5=A4=9F=E5=AE=8C=E7=BE=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/behavior/FlintAndSteelItemBehavior.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index 03b3b822a..9d46867ed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -81,7 +81,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { } BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()); // 点击的是方块上面,则只需要判断shift和可交互 - if (context.getClickedFace() == Direction.UP) { + if (direction == Direction.UP) { // 客户端层面必须可交互 if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { @@ -141,6 +141,15 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { if (BlockStateUtils.isBurnable(nearbyBlockState)) { return InteractionResult.PASS; } + try { + if (dir == Direction.DOWN && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + nearbyBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(relPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)) { + return InteractionResult.PASS; + } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } } } player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));