From a70931e051ae7abbf467bca24a4c7c8c2dce5334 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 3 May 2025 16:55:58 +0800 Subject: [PATCH 01/73] =?UTF-8?q?feat(entity):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=89=E5=8F=89=E6=88=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/ThrowableItemProjectileData.java | 12 ++++ .../plugin/command/feature/TestCommand.java | 35 ++++++++++- .../plugin/network/BukkitNetworkManager.java | 3 +- .../plugin/network/PacketConsumers.java | 51 +++++++++++++++- .../plugin/user/BukkitServerPlayer.java | 6 ++ .../craftengine/bukkit/util/Reflections.java | 59 ++++++++++++++++++- .../core/plugin/network/NetWorkUser.java | 2 + 7 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java new file mode 100644 index 000000000..6e40923dc --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import net.momirealms.craftengine.bukkit.util.Reflections; + +public class ThrowableItemProjectileData extends BaseEntityData { + public static final ThrowableItemProjectileData ItemStack = new ThrowableItemProjectileData<>(8, EntityDataValue.Serializers$ITEM_STACK, Reflections.instance$ItemStack$Air); + + + public ThrowableItemProjectileData(int id, Object serializer, T defaultValue) { + super(id, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 5e1ae7447..5c8102617 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,13 +1,25 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; public class TestCommand extends BukkitCommandFeature { @@ -19,9 +31,26 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) + .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + } + })) + .required("interpolationDelay", IntegerParser.integerParser()) + .required("transformationInterpolationDuration", IntegerParser.integerParser()) + .required("positionRotationInterpolationDuration", IntegerParser.integerParser()) .handler(context -> { Player player = context.sender(); - player.getInventory().addItem(BukkitItemManager.instance().createWrappedItem(Key.from("default:topaz"), null).getItem()); + NamespacedKey namespacedKey = context.get("id"); + var item = ItemStack.of(Material.TRIDENT); + item.editPersistentDataContainer(container -> { + container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")), PersistentDataType.STRING, namespacedKey.asString()); + container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")), PersistentDataType.INTEGER, context.get("interpolationDelay")); + container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")), PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); + container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")), PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); + }); + player.getInventory().addItem(item); }); } 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 d485c0da4..fdeae8450 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 @@ -152,6 +152,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket); registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); + registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket); registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); @@ -170,7 +171,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA_BYTEBUFFER, this.packetIds.clientboundSetEntityDataPacket()); } public static BukkitNetworkManager instance() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 0b9b202fa..fd9d35cb3 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 @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.network; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.papermc.paper.persistence.PersistentDataContainerView; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslationArgument; @@ -9,8 +10,10 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; @@ -48,8 +51,10 @@ import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; +import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; @@ -1590,6 +1595,32 @@ public class PacketConsumers { if (furniture != null) { event.setCancelled(true); } + } else if (entityType == Reflections.instance$EntityType$TRIDENT) { + int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); + Player player = (Player) user.platformPlayer(); + Trident trident = (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); + PersistentDataContainerView container = trident.getItemStack().getPersistentDataContainer(); + if (container == null) return; + String customTrident = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")), PersistentDataType.STRING); + int interpolationDelay = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")), PersistentDataType.INTEGER); + int transformationInterpolationDuration = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")), PersistentDataType.INTEGER); + int positionRotationInterpolationDuration = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")), PersistentDataType.INTEGER); + if (customTrident == null) return; + Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); + List itemDisplayValues = new ArrayList<>(); + Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); + ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); + if (VersionHelper.isOrAbove1_20_2()) { + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues); + } else { + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); + } + ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); + user.tridentView().put(entityId, itemDisplayValues); + event.addDelayedTask(() -> { + user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); + }); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); @@ -1600,6 +1631,12 @@ public class PacketConsumers { public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); + // if (user.tridentView().contains(entityId)) { + // if (!VersionHelper.isOrAbove1_21_3()) return; + // Object values = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); + // user.sendPacket(Reflections.constructor$ClientboundTeleportEntityPacket.newInstance(entityId, values, Set.of(), false), true); + // Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sync entity position: " + values)); + // } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); } @@ -1628,6 +1665,7 @@ public class PacketConsumers { int entityId = intList.getInt(i); user.entityView().remove(entityId); List entities = user.furnitureView().remove(entityId); + user.tridentView().remove(entityId); if (entities == null) continue; for (int subEntityId : entities) { isChange = true; @@ -1979,7 +2017,7 @@ public class PacketConsumers { }; @SuppressWarnings("unchecked") - public static final BiConsumer SET_ENTITY_DATA = (user, event) -> { + public static final BiConsumer SET_ENTITY_DATA_BYTEBUFFER = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); @@ -2301,4 +2339,15 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e); } }; + + public static final TriConsumer SET_ENTITY_DATA = (user, event, packet) -> { + try { + int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); + if (user.tridentView().containsKey(entityId)) { + event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId))); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); + } + }; } 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 13341b5b2..4727bc075 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 @@ -90,6 +90,7 @@ public class BukkitServerPlayer extends Player { // for better fake furniture visual sync private final Map> furnitureView = new ConcurrentHashMap<>(); private final Map entityTypeView = new ConcurrentHashMap<>(); + private final Map> tridentView = new ConcurrentHashMap<>(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -723,6 +724,11 @@ public class BukkitServerPlayer extends Player { return this.entityTypeView; } + @Override + public Map> tridentView() { + return this.tridentView; + } + public void setResendSound() { resentSoundTick = gameTicks(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 85165e2e5..eba11c579 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -558,7 +558,6 @@ public class Reflections { ) ); - @Deprecated public static final Field field$ClientboundAddEntityPacket$type = requireNonNull( ReflectionUtils.getDeclaredField( clazz$ClientboundAddEntityPacket, clazz$EntityType, 0 @@ -3811,6 +3810,8 @@ public class Reflections { public static final Object instance$EntityType$INTERACTION; public static final Object instance$EntityType$SHULKER; public static final Object instance$EntityType$OAK_BOAT; + public static final Object instance$EntityType$TRIDENT; + public static final Object instance$EntityType$SNOWBALL; static { try { @@ -3830,6 +3831,10 @@ public class Reflections { instance$EntityType$ARMOR_STAND = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, armorStand); Object oakBoat = VersionHelper.isOrAbove1_21_2() ? FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "oak_boat") : FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "boat"); instance$EntityType$OAK_BOAT = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, oakBoat); + Object trident = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "trident"); + instance$EntityType$TRIDENT = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, trident); + Object snowball = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "snowball"); + instance$EntityType$SNOWBALL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, snowball); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6615,4 +6620,56 @@ public class Reflections { BukkitReflectionUtils.assembleCBClass("block.CraftBlockStates$BlockEntityStateFactory") ) ); + + public static final Field field$clazz$ClientboundSetEntityDataPacket$id = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundSetEntityDataPacket, int.class, 0 + ) + ); + + // public static final Class clazz$PositionMoveRotation = + // ReflectionUtils.getClazz( + // BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation") + // ); + // + // public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) + // .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0)) + // .orElse(null); + // + // public static final Class clazz$ClientboundTeleportEntityPacket = requireNonNull( + // BukkitReflectionUtils.findReobfOrMojmapClass( + // "network.protocol.game.PacketPlayOutEntityTeleport", + // "network.protocol.game.ClientboundTeleportEntityPacket" + // ) + // ); + // + // /** + // * 实体移动数据包 + // * + // *

1.20 ~ 1.21.1 版本传入参数:

+ // *
    + // *
  • {@code FriendlyByteBuf} 需要按顺序写入: + // *
      + // *
    • {@code id} - VarInt 实体ID
    • + // *
    • {@code x} - Double X坐标
    • + // *
    • {@code y} - Double Y坐标
    • + // *
    • {@code z} - Double Z坐标
    • + // *
    • {@code yRot} - Byte 垂直旋转角度
    • + // *
    • {@code xRot} - Byte 水平旋转角度
    • + // *
    • {@code onGround} - Boolean 着地状态
    • + // *
    + // *
  • + // *
+ // * + // *

1.21.2+ 版本传入参数:

+ // *
    + // *
  • {@code id} - int 实体ID
  • + // *
  • {@code PositionMoveRotation change} - 位置和移动向量和旋转
  • + // *
  • {@code Set relatives} - 相对坐标标记集合
  • + // *
  • {@code onGround} - boolean 着地状态
  • + // *
+ // */ + // public static final Constructor constructor$ClientboundTeleportEntityPacket = requireNonNull( + // ReflectionUtils.getConstructor(clazz$ClientboundTeleportEntityPacket, VersionHelper.isOrAbove1_21_2() ? 0 : 1) + // ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index a88dd7c6a..b1952a648 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -46,6 +46,8 @@ public interface NetWorkUser { Map entityView(); + Map> tridentView(); + boolean clientModEnabled(); void setClientModState(boolean enable); From 340c819f4b87340786a8be348e09a7d9a8703d17 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 3 May 2025 17:02:15 +0800 Subject: [PATCH 02/73] =?UTF-8?q?feat(entity):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=89=E5=8F=89=E6=88=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) 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 fd9d35cb3..054db860c 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 @@ -1600,12 +1600,18 @@ public class PacketConsumers { Player player = (Player) user.platformPlayer(); Trident trident = (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); PersistentDataContainerView container = trident.getItemStack().getPersistentDataContainer(); - if (container == null) return; - String customTrident = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")), PersistentDataType.STRING); - int interpolationDelay = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")), PersistentDataType.INTEGER); - int transformationInterpolationDuration = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")), PersistentDataType.INTEGER); - int positionRotationInterpolationDuration = container.get(Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")), PersistentDataType.INTEGER); + NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); + NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); + NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); + NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); + String customTrident = container.get(customTridentKey, PersistentDataType.STRING); + Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); + Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); + Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); if (customTrident == null) return; + if (interpolationDelay == null) return; + if (transformationInterpolationDuration == null) return; + if (positionRotationInterpolationDuration == null) return; Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); List itemDisplayValues = new ArrayList<>(); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); From 5f1e1173115c7f42ffbd8daf0b0fe53e0fb2332e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 3 May 2025 17:12:52 +0800 Subject: [PATCH 03/73] =?UTF-8?q?feat(entity):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=89=E5=8F=89=E6=88=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 16 ++++++++++++---- .../bukkit/plugin/network/PacketConsumers.java | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 5c8102617..181124096 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -14,6 +14,7 @@ import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.ByteParser; import org.incendo.cloud.parser.standard.IntegerParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; @@ -40,15 +41,22 @@ public class TestCommand extends BukkitCommandFeature { .required("interpolationDelay", IntegerParser.integerParser()) .required("transformationInterpolationDuration", IntegerParser.integerParser()) .required("positionRotationInterpolationDuration", IntegerParser.integerParser()) + .required("displayType", ByteParser.byteParser()) .handler(context -> { Player player = context.sender(); NamespacedKey namespacedKey = context.get("id"); var item = ItemStack.of(Material.TRIDENT); + NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); + NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); + NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); + NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); + NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); item.editPersistentDataContainer(container -> { - container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")), PersistentDataType.STRING, namespacedKey.asString()); - container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")), PersistentDataType.INTEGER, context.get("interpolationDelay")); - container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")), PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); - container.set(Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")), PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); + container.set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); + container.set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); + container.set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); + container.set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); + container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); }); player.getInventory().addItem(item); }); 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 054db860c..5ca00aadd 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 @@ -1604,14 +1604,13 @@ public class PacketConsumers { NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); + NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); String customTrident = container.get(customTridentKey, PersistentDataType.STRING); Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); + Byte displayType = container.get(displayTypeKey, PersistentDataType.BYTE); if (customTrident == null) return; - if (interpolationDelay == null) return; - if (transformationInterpolationDuration == null) return; - if (positionRotationInterpolationDuration == null) return; Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); List itemDisplayValues = new ArrayList<>(); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); @@ -1623,6 +1622,7 @@ public class PacketConsumers { ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); } ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(displayType, itemDisplayValues); user.tridentView().put(entityId, itemDisplayValues); event.addDelayedTask(() -> { user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); From 7b2b56e836a7758f3ab53113b7d7392fb49390ca Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 4 May 2025 17:09:28 +0800 Subject: [PATCH 04/73] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8via=E8=BF=9B=E6=9C=8D=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E9=80=89=E5=8F=96=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 15 +++++----- .../craftengine/bukkit/util/Reflections.java | 30 +++++++++---------- gradle.properties | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) 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 16d0cfa9f..0b2159d8f 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 @@ -36,6 +36,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetworkManager; +import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -1344,7 +1345,7 @@ public class PacketConsumers { // When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue. public static final TriConsumer SET_CREATIVE_SLOT = (user, event, packet) -> { try { - if (VersionHelper.isOrAbove1_21_4()) return; + if (ProtocolVersionUtils.isVersionNewerThan(user.protocolVersion(), ProtocolVersion.V1_21_4)) return; if (!user.isOnline()) return; BukkitServerPlayer player = (BukkitServerPlayer) user; if (VersionHelper.isFolia()) { @@ -1612,6 +1613,7 @@ public class PacketConsumers { Byte displayType = container.get(displayTypeKey, PersistentDataType.BYTE); if (customTrident == null) return; Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); + // System.out.println(packet); List itemDisplayValues = new ArrayList<>(); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); @@ -1637,12 +1639,11 @@ public class PacketConsumers { public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); - // if (user.tridentView().contains(entityId)) { - // if (!VersionHelper.isOrAbove1_21_3()) return; - // Object values = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); - // user.sendPacket(Reflections.constructor$ClientboundTeleportEntityPacket.newInstance(entityId, values, Set.of(), false), true); - // Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sync entity position: " + values)); - // } + if (user.tridentView().containsKey(entityId)) { + if (!VersionHelper.isOrAbove1_21_3()) return; + Object values = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); + // Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sync entity position: " + values)); + } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index eba11c579..632d6775d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6627,21 +6627,21 @@ public class Reflections { ) ); - // public static final Class clazz$PositionMoveRotation = - // ReflectionUtils.getClazz( - // BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation") - // ); - // - // public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) - // .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0)) - // .orElse(null); - // - // public static final Class clazz$ClientboundTeleportEntityPacket = requireNonNull( - // BukkitReflectionUtils.findReobfOrMojmapClass( - // "network.protocol.game.PacketPlayOutEntityTeleport", - // "network.protocol.game.ClientboundTeleportEntityPacket" - // ) - // ); + public static final Class clazz$PositionMoveRotation = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation") + ); + + public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0)) + .orElse(null); + + public static final Class clazz$ClientboundTeleportEntityPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutEntityTeleport", + "network.protocol.game.ClientboundTeleportEntityPacket" + ) + ); // // /** // * 实体移动数据包 diff --git a/gradle.properties b/gradle.properties index 4783415e2..33dfae1b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 sparrow_nbt_version=0.7.1 -sparrow_util_version=0.39 +sparrow_util_version=0.40 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From 109205b23019952698351f803d4bf40a1d0394c5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 5 May 2025 01:14:59 +0800 Subject: [PATCH 05/73] =?UTF-8?q?feat(core):=20=E4=B8=BA=20SelfHostHttpSer?= =?UTF-8?q?ver=20=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=20URL=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 2 ++ .../craftengine/core/pack/host/impl/SelfHost.java | 3 ++- .../craftengine/core/pack/host/impl/SelfHostHttpServer.java | 6 ++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index da8cf0aa0..c4d0b734f 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -78,6 +78,8 @@ resource-pack: ip: "localhost" port: 8163 protocol: "http" + # The optional URL must be complete and include a trailing slash / at the end. + #url: "http://localhost:8163/" deny-non-minecraft-request: true one-time-token: true rate-limit: diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java index de38d7771..4a8fa9a9b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java @@ -66,6 +66,7 @@ public class SelfHost implements ResourcePackHost { if (port <= 0 || port > 65535) { throw new LocalizedException("warning.config.host.self.invalid_port", String.valueOf(port)); } + String url = arguments.get("url").toString(); boolean oneTimeToken = (boolean) arguments.getOrDefault("one-time-token", true); String protocol = arguments.getOrDefault("protocol", "http").toString(); boolean denyNonMinecraftRequest = (boolean) arguments.getOrDefault("deny-non-minecraft-request", true); @@ -76,7 +77,7 @@ public class SelfHost implements ResourcePackHost { maxRequests = ResourceConfigUtils.getAsInt(rateMap.getOrDefault("max-requests", 5), "max-requests"); resetInterval = ResourceConfigUtils.getAsInt(rateMap.getOrDefault("reset-interval", 20), "reset-interval") * 1000; } - selfHostHttpServer.updateProperties(ip, port, denyNonMinecraftRequest, protocol, maxRequests, resetInterval, oneTimeToken); + selfHostHttpServer.updateProperties(ip, port, url, denyNonMinecraftRequest, protocol, maxRequests, resetInterval, oneTimeToken); return INSTANCE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 6ce927583..785a00c6d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -48,6 +48,7 @@ public class SelfHostHttpServer { private String ip = "localhost"; private int port = -1; private String protocol = "http"; + private String url; private boolean denyNonMinecraft = true; private boolean useToken; @@ -57,12 +58,14 @@ public class SelfHostHttpServer { public void updateProperties(String ip, int port, + String url, boolean denyNonMinecraft, String protocol, int maxRequests, int resetInternal, boolean token) { this.ip = ip; + this.url = url; this.denyNonMinecraft = denyNonMinecraft; this.protocol = protocol; this.rateLimit = maxRequests; @@ -112,6 +115,9 @@ public class SelfHostHttpServer { } public String url() { + if (this.url != null && !this.url.isEmpty()) { + return this.url; + } return this.protocol + "://" + this.ip + ":" + this.port + "/"; } From 99e2d5cd36b48efbc1f3a66b7cb84cca1f0d64ef Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 5 May 2025 09:02:39 +0800 Subject: [PATCH 06/73] =?UTF-8?q?feat(core):=20=E4=B8=80=E4=BA=9B=E5=AF=B9?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8C=85=E6=89=98=E7=AE=A1=E5=92=8C=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8C=85=E7=94=9F=E6=88=90=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/translations/en.yml | 4 +++- .../loader/src/main/resources/translations/zh_cn.yml | 4 +++- .../bukkit/plugin/network/PacketConsumers.java | 2 +- .../craftengine/core/pack/AbstractPackManager.java | 6 ++++++ .../craftengine/core/pack/host/impl/SelfHost.java | 8 +++++++- .../core/plugin/network/ProtocolVersion.java | 4 ++++ .../craftengine/core/util/ProtocolVersionUtils.java | 10 ---------- gradle.properties | 2 +- 8 files changed, 25 insertions(+), 15 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 6011167dd..eae6aee64 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -272,6 +272,7 @@ warning.config.host.s3.missing_secret: "Issue found in config.yml at 're warning.config.host.s3.missing_upload_path: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'upload-path' argument for s3 host." warning.config.host.self.missing_ip: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'ip' argument for self host." warning.config.host.self.invalid_port: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid port '' for self host." +warning.config.host.self.invalid_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid url '' for self host." warning.config.host.gitlab.missing_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'gitlab-url' argument for gitlab host." warning.config.host.gitlab.missing_token: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'access-token' argument for gitlab host." warning.config.host.gitlab.missing_project: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'project-id' argument for gitlab host." @@ -291,4 +292,5 @@ warning.config.conflict_matcher.inverted.missing_term: "Issue found in c warning.config.conflict_matcher.all_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'all_of' matcher." warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." -warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." +warning.resource_pack.generation_in_progress: "Resource pack generation is already in progress. Please wait until it finishes." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index d2dd13dd8..1a1152fc3 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -274,6 +274,7 @@ warning.config.host.s3.missing_secret: "在 config.yml 的 'resource-pac warning.config.host.s3.missing_upload_path: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'upload-path' 参数" warning.config.host.self.missing_ip: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管缺少必需的 'ip' 参数" warning.config.host.self.invalid_port: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的端口 '' 无效" +warning.config.host.self.invalid_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的 URL '' 无效" warning.config.host.gitlab.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'gitlab-url' 参数" warning.config.host.gitlab.missing_token: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'access-token' 参数" warning.config.host.gitlab.missing_project: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - GitLab 托管缺少必需的 'project-id' 参数" @@ -293,4 +294,5 @@ warning.config.conflict_matcher.inverted.missing_term: "在 config.yml warning.config.conflict_matcher.all_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 全匹配器缺少必需的 'terms' 参数" warning.config.conflict_matcher.any_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 任一匹配器缺少必需的 'terms' 参数" warning.config.conflict_resolution.missing_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案缺少必需的 'type' 参数" -warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" +warning.resource_pack.generation_in_progress: "资源包正在生成中, 请等待完成再试" \ No newline at end of file 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 08578f7dc..9858ea30a 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 @@ -1354,7 +1354,7 @@ public class PacketConsumers { // When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue. public static final TriConsumer SET_CREATIVE_SLOT = (user, event, packet) -> { try { - if (ProtocolVersionUtils.isVersionNewerThan(user.protocolVersion(), ProtocolVersion.V1_21_4)) return; + if (user.protocolVersion().isVersionNewerThan(ProtocolVersion.V1_21_4)) return; if (!user.isOnline()) return; BukkitServerPlayer player = (BukkitServerPlayer) user; if (VersionHelper.isFolia()) { 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 ff722cd59..43529efe4 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 @@ -73,6 +73,7 @@ public abstract class AbstractPackManager implements PackManager { private final TreeMap> cachedConfigs = new TreeMap<>(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; + private boolean generateResourcePack = false; public AbstractPackManager(CraftEngine plugin, BiConsumer eventDispatcher) { this.plugin = plugin; @@ -486,6 +487,10 @@ public abstract class AbstractPackManager implements PackManager { @Override public void generateResourcePack() { + if (this.generateResourcePack) { + throw new LocalizedException("warning.resource_pack.generation_in_progress"); + } + this.generateResourcePack = true; this.plugin.logger().info("Generating resource pack..."); long start = System.currentTimeMillis(); // get the target location @@ -547,6 +552,7 @@ public abstract class AbstractPackManager implements PackManager { long end = System.currentTimeMillis(); this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); this.eventDispatcher.accept(generatedPackPath, zipFile); + this.generateResourcePack = false; } private void generateParticle(Path generatedPackPath) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java index 4a8fa9a9b..acfdd0800 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java @@ -66,7 +66,13 @@ public class SelfHost implements ResourcePackHost { if (port <= 0 || port > 65535) { throw new LocalizedException("warning.config.host.self.invalid_port", String.valueOf(port)); } - String url = arguments.get("url").toString(); + String url = arguments.getOrDefault("url", "").toString(); + if (!url.isEmpty()) { + if (!url.startsWith("http://") && !url.startsWith("https://")) { + throw new LocalizedException("warning.config.host.self.invalid_url", url); + } + if (!url.endsWith("/")) url += "/"; + } boolean oneTimeToken = (boolean) arguments.getOrDefault("one-time-token", true); String protocol = arguments.getOrDefault("protocol", "http").toString(); boolean denyNonMinecraftRequest = (boolean) arguments.getOrDefault("deny-non-minecraft-request", true); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java index c692c6da6..f9e3c4b05 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java @@ -32,6 +32,10 @@ public enum ProtocolVersion { return name; } + public boolean isVersionNewerThan(ProtocolVersion targetVersion) { + return this.getId() >= targetVersion.getId(); + } + public static ProtocolVersion getByName(String name) { for (ProtocolVersion version : values()) { if (version.getName().equals(name)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java deleted file mode 100644 index 8372e1117..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ProtocolVersionUtils.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; - -public class ProtocolVersionUtils { - - public static boolean isVersionNewerThan(ProtocolVersion version, ProtocolVersion targetVersion) { - return version.getId() >= targetVersion.getId(); - } -} diff --git a/gradle.properties b/gradle.properties index 833e03059..962420ca7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.53-beta.3 config_version=31 -lang_version=10 +lang_version=11 project_group=net.momirealms latest_supported_version=1.21.5 From 82d809ff5abf9e90807a84117efb13d75b495083 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 5 May 2025 09:25:29 +0800 Subject: [PATCH 07/73] =?UTF-8?q?feat(core):=20=E4=B8=80=E4=BA=9B=E5=AF=B9?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8C=85=E6=89=98=E7=AE=A1=E5=92=8C=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8C=85=E7=94=9F=E6=88=90=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/command/feature/ReloadCommand.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index 00056ba91..079dcf240 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.MessageConstants; import org.bukkit.command.CommandSender; import org.incendo.cloud.Command; @@ -68,7 +69,9 @@ public class ReloadCommand extends BukkitCommandFeature { long time2 = System.currentTimeMillis(); long packTime = time2 - time1; handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_SUCCESS, Component.text(packTime)); - + } catch (LocalizedException e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_FAILURE); + plugin().logger().warn(e.getMessage()); } catch (Exception e) { handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_FAILURE); plugin().logger().warn("Failed to generate resource pack", e); @@ -89,6 +92,9 @@ public class ReloadCommand extends BukkitCommandFeature { Component.text(reloadResult.syncTime()), Component.text(packTime) ); + } catch (LocalizedException e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn(e.getMessage()); } finally { RELOAD_PACK_FLAG = false; } From add7fecd34114251b6beb3eac52ba6d6b83b2518 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 5 May 2025 09:50:40 +0800 Subject: [PATCH 08/73] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8C=85=E7=94=9F=E6=88=90=E9=80=9F=E5=BA=A6=E8=BF=87?= =?UTF-8?q?=E6=85=A2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/AbstractPackManager.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) 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 43529efe4..448873dca 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 @@ -44,6 +44,7 @@ import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.stream.Stream; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; @@ -142,6 +143,7 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { + initFileSystemProvider(); List> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting"); if (list == null || list.isEmpty()) { this.resourcePackHost = NoneHost.INSTANCE; @@ -485,6 +487,36 @@ public abstract class AbstractPackManager implements PackManager { } } + private static void initFileSystemProvider() { + String osName = System.getProperty("os.name").toLowerCase(); + String providerClass = null; + if (osName.contains("win")) { + providerClass = "sun.nio.fs.WindowsFileSystemProvider"; + } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { + providerClass = "sun.nio.fs.LinuxFileSystemProvider"; + } else if (osName.contains("mac")) { + providerClass = "sun.nio.fs.MacOSXFileSystemProvider"; + } + if (providerClass != null) { + try { + System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", providerClass); + } catch (Exception ignored) {} + } + } + + private static void deleteDirectory(Path folder) throws IOException { + if (!Files.exists(folder)) return; + try (Stream walk = Files.walk(folder)) { + walk.sorted(Comparator.reverseOrder()) + .parallel() + .forEach(path -> { + try { + Files.delete(path); + } catch (IOException ignored) {} + }); + } + } + @Override public void generateResourcePack() { if (this.generateResourcePack) { @@ -499,7 +531,7 @@ public abstract class AbstractPackManager implements PackManager { .resolve("resource_pack"); try { - org.apache.commons.io.FileUtils.deleteDirectory(generatedPackPath.toFile()); + deleteDirectory(generatedPackPath); } catch (IOException e) { this.plugin.logger().severe("Error deleting previous resource pack", e); } From 2ba21c2dce280d4df7f5860b18c2b611618d6a28 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 6 May 2025 15:47:36 +0800 Subject: [PATCH 09/73] =?UTF-8?q?refactor(core):=20=E6=92=A4=E9=94=80?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/translations/en.yml | 3 +-- bukkit/loader/src/main/resources/translations/zh_cn.yml | 3 +-- .../craftengine/core/pack/AbstractPackManager.java | 6 ------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 77375beb6..96cd97723 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -293,5 +293,4 @@ warning.config.conflict_matcher.all_of.missing_terms: "Issue found in co warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." -warning.resource_pack.generation_in_progress: "Resource pack generation is already in progress. Please wait until it finishes." \ No newline at end of file +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 1a1152fc3..f191e0076 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -294,5 +294,4 @@ warning.config.conflict_matcher.inverted.missing_term: "在 config.yml warning.config.conflict_matcher.all_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 全匹配器缺少必需的 'terms' 参数" warning.config.conflict_matcher.any_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 任一匹配器缺少必需的 'terms' 参数" warning.config.conflict_resolution.missing_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案缺少必需的 'type' 参数" -warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" -warning.resource_pack.generation_in_progress: "资源包正在生成中, 请等待完成再试" \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" \ No newline at end of file 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 448873dca..b582cb7d9 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 @@ -74,7 +74,6 @@ public abstract class AbstractPackManager implements PackManager { private final TreeMap> cachedConfigs = new TreeMap<>(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; - private boolean generateResourcePack = false; public AbstractPackManager(CraftEngine plugin, BiConsumer eventDispatcher) { this.plugin = plugin; @@ -519,10 +518,6 @@ public abstract class AbstractPackManager implements PackManager { @Override public void generateResourcePack() { - if (this.generateResourcePack) { - throw new LocalizedException("warning.resource_pack.generation_in_progress"); - } - this.generateResourcePack = true; this.plugin.logger().info("Generating resource pack..."); long start = System.currentTimeMillis(); // get the target location @@ -584,7 +579,6 @@ public abstract class AbstractPackManager implements PackManager { long end = System.currentTimeMillis(); this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); this.eventDispatcher.accept(generatedPackPath, zipFile); - this.generateResourcePack = false; } private void generateParticle(Path generatedPackPath) { From 658f6cc5313812ea3b3b5055078f781583f5424b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 8 May 2025 00:50:13 +0800 Subject: [PATCH 10/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/BukkitCraftEngine.java | 11 +------- .../DebugIsSectionInjectedCommand.java | 5 ---- .../bukkit/plugin/gui/BukkitGuiManager.java | 28 ------------------- .../plugin/injector/BukkitInjector.java | 5 ++-- .../plugin/network/BukkitNetworkManager.java | 4 +++ .../plugin/user/BukkitServerPlayer.java | 12 ++++++++ .../craftengine/bukkit/util/LightUtils.java | 7 +---- .../bukkit/world/BukkitCEWorld.java | 17 +++++++++-- .../bukkit/world/BukkitWorldManager.java | 23 ++++++++++----- .../core/util/SectionPosUtils.java | 9 ++---- .../craftengine/core/world/CEWorld.java | 12 ++++---- gradle.properties | 2 +- .../craftengine/mod/CraftEnginePlugin.java | 1 - 13 files changed, 61 insertions(+), 75 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index fe7f48e8f..6d63a4cd7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -40,7 +40,6 @@ import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; @@ -192,15 +191,7 @@ public class BukkitCraftEngine extends CraftEngine { new Metrics(this.bootstrap(), 24333); } // tick task - if (VersionHelper.isFolia()) { - this.tickTask = this.scheduler().sync().runRepeating(() -> { - for (BukkitServerPlayer serverPlayer : networkManager().onlineUsers()) { - org.bukkit.entity.Player player = serverPlayer.platformPlayer(); - Location location = player.getLocation(); - scheduler().sync().run(serverPlayer::tick, player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); - } - }, 1, 1); - } else { + if (!VersionHelper.isFolia()) { this.tickTask = this.scheduler().sync().runRepeating(() -> { for (BukkitServerPlayer serverPlayer : networkManager().onlineUsers()) { serverPlayer.tick(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java index b14e164e9..549d9d5f2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugIsSectionInjectedCommand.java @@ -7,15 +7,10 @@ import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.world.chunk.CESection; import org.bukkit.Chunk; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.Command; -import org.incendo.cloud.parser.standard.StringParser; public class DebugIsSectionInjectedCommand extends BukkitCommandFeature { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index 2b6d78874..79b1528a5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -1,13 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.gui; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.core.plugin.gui.AbstractGui; import net.momirealms.craftengine.core.plugin.gui.Gui; import net.momirealms.craftengine.core.plugin.gui.GuiManager; import net.momirealms.craftengine.core.plugin.gui.Inventory; -import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; -import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -19,7 +16,6 @@ import org.bukkit.event.inventory.InventoryDragEvent; public class BukkitGuiManager implements GuiManager, Listener { private final BukkitCraftEngine plugin; - private SchedulerTask timerTask; public BukkitGuiManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -28,35 +24,11 @@ public class BukkitGuiManager implements GuiManager, Listener { @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap()); - this.timerTask = plugin.scheduler().sync().runRepeating(this::timerTask, 30, 30); } @Override public void disable() { HandlerList.unregisterAll(this); - if (this.timerTask != null && !this.timerTask.cancelled()) { - this.timerTask.cancel(); - } - } - - public void timerTask() { - if (VersionHelper.isFolia()) { - for (Player player : Bukkit.getOnlinePlayers()) { - this.plugin.scheduler().sync().run(() -> { - org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory(); - if (top.getHolder() instanceof CraftEngineInventoryHolder holder) { - holder.gui().onTimer(); - } - }, player.getWorld(), player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4); - } - } else { - for (Player player : Bukkit.getOnlinePlayers()) { - org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(player) : player.getOpenInventory().getTopInventory(); - if (top.getHolder() instanceof CraftEngineInventoryHolder holder) { - holder.gui().onTimer(); - } - } - } } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 9a54e77a1..60f26221c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -68,7 +68,6 @@ import java.lang.reflect.Modifier; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; @@ -827,8 +826,8 @@ public class BukkitInjector { if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) { CEWorld world = thisObj.ceChunk().world(); SectionPos sectionPos = thisObj.cePos(); - Set posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight)); - world.sectionLightUpdated(posSet); + List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight)); + world.sectionLightUpdated(pos); } } 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 d485c0da4..c67b74ea5 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 @@ -185,6 +185,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes user.setPlayer(player); this.onlineUsers.put(player.getUniqueId(), user); this.resetUserArray(); + if (VersionHelper.isFolia()) { + player.getScheduler().runAtFixedRate(plugin.bootstrap(), (t) -> user.tick(), + () -> plugin.debug(() -> "Player " + player.getName() + "'s entity scheduler is retired"), 1, 1); + } } } 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 c3352106c..b72d8beef 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 @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineInventoryHolder; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.BlockSettings; @@ -323,6 +324,7 @@ public class BukkitServerPlayer extends Player { public void tick() { // not fully online if (serverPlayer() == null) return; + if (VersionHelper.isFolia()) { try { Object serverPlayer = serverPlayer(); @@ -334,6 +336,9 @@ public class BukkitServerPlayer extends Player { } else { this.gameTicks = FastNMS.INSTANCE.field$MinecraftServer$currentTick(); } + if (this.gameTicks % 15 == 0) { + this.updateGUI(); + } if (this.isDestroyingBlock) { this.tickBlockDestroy(); } @@ -350,6 +355,13 @@ public class BukkitServerPlayer extends Player { } } + private void updateGUI() { + org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(platformPlayer()) : platformPlayer().getOpenInventory().getTopInventory(); + if (top.getHolder() instanceof CraftEngineInventoryHolder holder) { + holder.gui().onTimer(); + } + } + @Override public float getDestroyProgress(Object blockState, BlockPos pos) { return FastNMS.INSTANCE.method$BlockStateBase$getDestroyProgress(blockState, serverPlayer(), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformPlayer().getWorld()), LocationUtils.toBlockPos(pos)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java index 7d84c1a83..a7ec85455 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java @@ -23,16 +23,11 @@ public class LightUtils { List players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(chunkHolder); if (players.isEmpty()) continue; Object lightEngine = Reflections.field$ChunkHolder$lightEngine.get(chunkHolder); - BitSet blockChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$blockChangedLightSectionFilter.get(chunkHolder); - blockChangedLightSectionFilter.or(entry.getValue()); - BitSet skyChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$skyChangedLightSectionFilter.get(chunkHolder); Object chunkPos = FastNMS.INSTANCE.constructor$ChunkPos((int) chunkKey, (int) (chunkKey >> 32)); - Object lightPacket = FastNMS.INSTANCE.constructor$ClientboundLightUpdatePacket(chunkPos, lightEngine, skyChangedLightSectionFilter, blockChangedLightSectionFilter); + Object lightPacket = FastNMS.INSTANCE.constructor$ClientboundLightUpdatePacket(chunkPos, lightEngine, entry.getValue(), entry.getValue()); for (Object player : players) { FastNMS.INSTANCE.sendPacket(player, lightPacket); } - blockChangedLightSectionFilter.clear(); - skyChangedLightSectionFilter.clear(); } } catch (Exception e) { CraftEngine.instance().logger().warn("Could not update light for world " + world.getName()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index b9070e694..aadb65e6f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -4,10 +4,13 @@ import net.momirealms.craftengine.bukkit.util.LightUtils; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.SectionPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import java.util.HashSet; + public class BukkitCEWorld extends CEWorld { public BukkitCEWorld(World world, StorageAdaptor adaptor) { @@ -20,9 +23,19 @@ public class BukkitCEWorld extends CEWorld { @Override public void tick() { + HashSet poses; + synchronized (super.updatedSectionSet) { + poses = new HashSet<>(super.updatedSectionSet); + super.updatedSectionSet.clear(); + } if (Config.enableLightSystem()) { - LightUtils.updateChunkLight((org.bukkit.World) world.platformWorld(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1)); - super.updatedSectionPositions.clear(); + LightUtils.updateChunkLight( + (org.bukkit.World) world.platformWorld(), + SectionPosUtils.toMap(poses, + world.worldHeight().getMinSection() - 1, + world.worldHeight().getMaxSection() + 1 + ) + ); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index d527a0ab7..afa8d1159 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; public class BukkitWorldManager implements WorldManager, Listener { @@ -45,6 +46,7 @@ public class BukkitWorldManager implements WorldManager, Listener { private UUID lastVisitedUUID; private CEWorld lastVisitedWorld; private StorageAdaptor storageAdaptor; + private boolean isTicking = false; public BukkitWorldManager(BukkitCraftEngine plugin) { instance = this; @@ -90,12 +92,20 @@ public class BukkitWorldManager implements WorldManager, Listener { public void delayedInit() { // events and tasks - Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap()); - this.tickTask = plugin.scheduler().sync().runRepeating(() -> { - for (CEWorld world : worldArray) { - world.tick(); + Bukkit.getPluginManager().registerEvents(this, this.plugin.bootstrap()); + this.tickTask = this.plugin.scheduler().asyncRepeating(() -> { + try { + if (this.isTicking) { + return; + } + this.isTicking = true; + for (CEWorld world : this.worldArray) { + world.tick(); + } + } finally { + this.isTicking = false; } - }, 1, 1); + }, 50, 50, TimeUnit.MILLISECONDS); // load loaded chunks this.worldMapLock.writeLock().lock(); try { @@ -125,7 +135,6 @@ public class BukkitWorldManager implements WorldManager, Listener { if (this.tickTask != null && !this.tickTask.cancelled()) { this.tickTask.cancel(); } - for (World world : Bukkit.getWorlds()) { CEWorld ceWorld = getWorld(world.getUID()); for (Chunk chunk : world.getLoadedChunks()) { @@ -299,7 +308,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } } } - if (unsaved && !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)) { + if (unsaved /*&& !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)*/) { FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk); } ceChunk.unload(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SectionPosUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/SectionPosUtils.java index 230a0419e..4640a4140 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SectionPosUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SectionPosUtils.java @@ -4,10 +4,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.SectionPos; -import java.util.BitSet; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class SectionPosUtils { @@ -46,8 +43,8 @@ public class SectionPosUtils { return nearby; } - public static Set calculateAffectedRegions(int sx, int sy, int sz, int x) { - Set regions = new HashSet<>(); + public static List calculateAffectedRegions(int sx, int sy, int sz, int x) { + List regions = new ArrayList<>(); int rxStart = (sx - x) >> 4; int rxEnd = (sx + x) >> 4; int ryStart = (sy - x) >> 4; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index e36abc7ce..2a636bd69 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -9,10 +9,10 @@ import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.Collections; -import java.util.HashSet; +import java.util.Collection; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; public abstract class CEWorld { @@ -22,7 +22,7 @@ public abstract class CEWorld { protected final WorldDataStorage worldDataStorage; protected final ReentrantReadWriteLock loadedChunkMapLock = new ReentrantReadWriteLock(); protected final WorldHeight worldHeightAccessor; - protected final Set updatedSectionPositions = Collections.synchronizedSet(new HashSet<>()); + protected final Set updatedSectionSet = ConcurrentHashMap.newKeySet(128); private CEChunk lastChunk; private long lastChunkPos; @@ -165,11 +165,11 @@ public abstract class CEWorld { } public void sectionLightUpdated(SectionPos pos) { - this.updatedSectionPositions.add(pos); + this.updatedSectionSet.add(pos); } - public void sectionLightUpdated(Set pos) { - this.updatedSectionPositions.addAll(pos); + public void sectionLightUpdated(Collection pos) { + this.updatedSectionSet.addAll(pos); } public abstract void tick(); diff --git a/gradle.properties b/gradle.properties index f57da2123..eeaecc408 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.53 +project_version=0.0.53.1 config_version=32 lang_version=12 project_group=net.momirealms diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java index c0b7d7bf1..6cb356a90 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/CraftEnginePlugin.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.mod; -import net.minecraft.world.level.chunk.LevelChunkSection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; From 50d052c42b611f00c7d6fe523a0bd4796dff0bc2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 8 May 2025 00:52:03 +0800 Subject: [PATCH 11/73] Update RegionFile.java --- .../craftengine/core/world/chunk/storage/RegionFile.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java index 0ee384791..b2e8ad51b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java @@ -11,7 +11,6 @@ import java.io.*; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; -import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; From 33f96267b39fc73ac91119a1464b841210bb066b Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 8 May 2025 06:21:06 +0800 Subject: [PATCH 12/73] =?UTF-8?q?feat(bukkit):=20=E8=BF=9B=E4=B8=80?= =?UTF-8?q?=E6=AD=A5=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 1.20 ~ 1.21.1 可以正常移动 1.21.2+ 需要补包 - 附魔的三叉戟和世界上有的三叉戟玩家离开再回来无法显示 --- .../plugin/command/feature/TestCommand.java | 39 ++++++++--- .../plugin/network/BukkitNetworkManager.java | 1 + .../plugin/network/PacketConsumers.java | 68 +++++++++++++++---- .../craftengine/bukkit/util/Reflections.java | 54 ++++++++++++++- .../craftengine/core/util/MCUtils.java | 13 ++++ 5 files changed, 150 insertions(+), 25 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 181124096..a934709aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; @@ -14,12 +17,12 @@ import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.ByteParser; import org.incendo.cloud.parser.standard.IntegerParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class TestCommand extends BukkitCommandFeature { @@ -29,6 +32,7 @@ public class TestCommand extends BukkitCommandFeature { } @Override + @SuppressWarnings("deprecation") public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) @@ -41,22 +45,37 @@ public class TestCommand extends BukkitCommandFeature { .required("interpolationDelay", IntegerParser.integerParser()) .required("transformationInterpolationDuration", IntegerParser.integerParser()) .required("positionRotationInterpolationDuration", IntegerParser.integerParser()) - .required("displayType", ByteParser.byteParser()) + // .required("displayType", ByteParser.byteParser()) + // .required("x", FloatParser.floatParser()) + // .required("y", FloatParser.floatParser()) + // .required("z", FloatParser.floatParser()) + // .required("w", FloatParser.floatParser()) .handler(context -> { Player player = context.sender(); NamespacedKey namespacedKey = context.get("id"); - var item = ItemStack.of(Material.TRIDENT); + ItemStack item = new ItemStack(Material.TRIDENT); NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); - NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); - item.editPersistentDataContainer(container -> { - container.set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); - container.set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); - container.set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); - container.set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); - container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); + // NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); + // NamespacedKey customTridentX = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_x")); + // NamespacedKey customTridentY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_y")); + // NamespacedKey customTridentZ = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_z")); + // NamespacedKey customTridentW = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_w")); + item.editMeta(meta -> { + meta.getPersistentDataContainer().set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); + meta.getPersistentDataContainer().set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); + meta.getPersistentDataContainer().set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); + meta.getPersistentDataContainer().set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); + // container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); + // container.set(customTridentX, PersistentDataType.FLOAT, context.get("x")); + // container.set(customTridentY, PersistentDataType.FLOAT, context.get("y")); + // container.set(customTridentZ, PersistentDataType.FLOAT, context.get("z")); + // container.set(customTridentW, PersistentDataType.FLOAT, context.get("w")); + Item ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null); + Optional customModelData = ceItem.customModelData(); + customModelData.ifPresent(meta::setCustomModelData); }); player.getInventory().addItem(item); }); 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 fdeae8450..ffd10dbdb 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 @@ -153,6 +153,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket); + registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY_ALL, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(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 a88d663ec..a8e27c484 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 @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.papermc.paper.persistence.PersistentDataContainerView; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslationArgument; @@ -56,10 +55,13 @@ import org.bukkit.entity.Player; import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; @@ -1616,23 +1618,28 @@ public class PacketConsumers { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); Player player = (Player) user.platformPlayer(); Trident trident = (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); - PersistentDataContainerView container = trident.getItemStack().getPersistentDataContainer(); + PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); + String customTrident = container.get(customTridentKey, PersistentDataType.STRING); + if (customTrident == null) return; + user.tridentView().put(entityId, List.of()); NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); - NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); - String customTrident = container.get(customTridentKey, PersistentDataType.STRING); Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); - Byte displayType = container.get(displayTypeKey, PersistentDataType.BYTE); - if (customTrident == null) return; + float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$yRot.getByte(packet)); + float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$xRot.getByte(packet)); + player.sendMessage("加载自定义三叉戟实体1: " + packet); Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); - // System.out.println(packet); + Reflections.field$ClientboundAddEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); + Reflections.field$ClientboundAddEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); List itemDisplayValues = new ArrayList<>(); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(0, 0, -2), itemDisplayValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(1, 1, 1, 1), itemDisplayValues); if (VersionHelper.isOrAbove1_20_2()) { ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues); @@ -1640,10 +1647,12 @@ public class PacketConsumers { ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); } ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(displayType, itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue((byte) 0, itemDisplayValues); user.tridentView().put(entityId, itemDisplayValues); + player.sendMessage("加载自定义三叉戟实体2: " + entityId); event.addDelayedTask(() -> { user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); + player.sendMessage("加载自定义三叉戟实体3: " + itemDisplayValues); }); } } catch (Exception e) { @@ -1651,14 +1660,22 @@ public class PacketConsumers { } }; - // 1.21.3+ + // 1.21.2+ public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); if (user.tridentView().containsKey(entityId)) { - if (!VersionHelper.isOrAbove1_21_3()) return; - Object values = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); - // Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sync entity position: " + values)); + Player player = (Player) user.platformPlayer(); + player.sendMessage("同步三叉戟实体位置: " + packet); + Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); + boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); + Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); + Object deltaMovement = Reflections.field$PositionMoveRotation$deltaMovement.get(positionMoveRotation); + float yRot = Reflections.field$PositionMoveRotation$yRot.getFloat(positionMoveRotation); + float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); + Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); + event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); + return; } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); @@ -1688,7 +1705,11 @@ public class PacketConsumers { int entityId = intList.getInt(i); user.entityView().remove(entityId); List entities = user.furnitureView().remove(entityId); - user.tridentView().remove(entityId); + var removeTrident = user.tridentView().remove(entityId); + if (removeTrident != null && !removeTrident.isEmpty()) { + Player player = (Player) user.platformPlayer(); + player.sendMessage("移除三叉戟实体: " + removeTrident); + } if (entities == null) continue; for (int subEntityId : entities) { isChange = true; @@ -2367,10 +2388,29 @@ public class PacketConsumers { try { int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); if (user.tridentView().containsKey(entityId)) { - event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId))); + Player player = (Player) user.platformPlayer(); + Object newPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId)); + player.sendMessage("设置三叉戟实体数据: " + newPacket); + event.replacePacket(newPacket); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); } }; + + public static final TriConsumer MOVE_ENTITY_ALL = (user, event, packet) -> { + try { + int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); + if (user.tridentView().containsKey(entityId)) { + float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); + float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); + Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); + Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); + Player player = (Player) user.platformPlayer(); + player.sendMessage("同步三叉戟实体位置: " + Math.clamp(-xRot, -90.0F, 90.0F) + ", " + -yRot); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 9023eef48..36f6b5a5c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -3984,7 +3984,7 @@ public class Reflections { ) ); - // 1.21.3+ + // 1.21.2+ public static final Class clazz$ClientboundEntityPositionSyncPacket = ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundEntityPositionSyncPacket") @@ -6635,16 +6635,68 @@ public class Reflections { BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation") ); + public static final Constructor constructor$PositionMoveRotation = Optional.ofNullable(clazz$PositionMoveRotation) + .map(it -> ReflectionUtils.getTheOnlyConstructor(it)) + .orElse(null); + public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0)) .orElse(null); + public static final Field field$ClientboundEntityPositionSyncPacket$onGround = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, boolean.class, 0)) + .orElse(null); + + public static final Field field$PositionMoveRotation$position = Optional.ofNullable(clazz$PositionMoveRotation) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 0)) + .orElse(null); + + public static final Field field$PositionMoveRotation$deltaMovement = Optional.ofNullable(clazz$PositionMoveRotation) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 1)) + .orElse(null); + + public static final Field field$PositionMoveRotation$yRot = Optional.ofNullable(clazz$PositionMoveRotation) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 0)) + .orElse(null); + + public static final Field field$PositionMoveRotation$xRot = Optional.ofNullable(clazz$PositionMoveRotation) + .map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 1)) + .orElse(null); + public static final Class clazz$ClientboundTeleportEntityPacket = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "network.protocol.game.PacketPlayOutEntityTeleport", "network.protocol.game.ClientboundTeleportEntityPacket" ) ); + + public static final Constructor constructor$ClientboundEntityPositionSyncPacket = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) + .map(it -> ReflectionUtils.getTheOnlyConstructor(it)) + .orElse(null); + + public static final Field field$ClientboundAddEntityPacket$xRot = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundAddEntityPacket, byte.class, 0 + ) + ); + + public static final Field field$ClientboundAddEntityPacket$yRot = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundAddEntityPacket, byte.class, 1 + ) + ); + + public static final Field field$ClientboundMoveEntityPacket$xRot = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundMoveEntityPacket, byte.class, 1 + ) + ); + + public static final Field field$ClientboundMoveEntityPacket$yRot = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundMoveEntityPacket, byte.class, 0 + ) + ); // // /** // * 实体移动数据包 diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 9669fe006..86f2093ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -184,4 +184,17 @@ public class MCUtils { } return next; } + + public static int floor(float value) { + int i = (int) value; + return value < (float)i ? i - 1 : i; + } + + public static byte packDegrees(float degrees) { + return (byte)floor(degrees * 256.0F / 360.0F); + } + + public static float unpackDegrees(byte degrees) { + return (float)(degrees * 360) / 256.0F; + } } From 8b2b3c8cf8be8aeff5b4f26113b20a6187ae2f2a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 8 May 2025 18:52:48 +0800 Subject: [PATCH 13/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D1.21.3=E7=9A=84?= =?UTF-8?q?=E7=B2=92=E5=AD=90=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/network/BukkitNetworkManager.java | 2 +- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 2 +- gradle.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index c67b74ea5..122246cb5 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 @@ -155,7 +155,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_21_3() ? PacketConsumers.LEVEL_PARTICLE_1_21_3 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); + registerByteBufPacketConsumer(VersionHelper.isOrAbove1_21_4() ? PacketConsumers.LEVEL_PARTICLE_1_21_4 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket()); registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket()); registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket()); 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 a5cb326fc..b91cbd887 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 @@ -1051,7 +1051,7 @@ public class PacketConsumers { } }; - public static final BiConsumer LEVEL_PARTICLE_1_21_3 = (user, event) -> { + public static final BiConsumer LEVEL_PARTICLE_1_21_4 = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); boolean overrideLimiter = buf.readBoolean(); diff --git a/gradle.properties b/gradle.properties index eeaecc408..978455b6b 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.53.1 +project_version=0.0.53.2 config_version=32 lang_version=12 project_group=net.momirealms From ef1caaa05afa367acd6de3d2f76ac5af3d591108 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 9 May 2025 02:05:02 +0800 Subject: [PATCH 14/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0special=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=94=9F=E6=88=90=EF=BC=8C=E5=AE=8C=E5=96=84special?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 3 ++- .../src/main/resources/translations/tr.yml | 1 - .../src/main/resources/translations/zh_cn.yml | 3 ++- .../item/factory/BukkitItemFactory.java | 2 +- .../core/pack/model/SpecialItemModel.java | 26 ++++++++++++++++--- .../pack/model/special/ChestSpecialModel.java | 4 ++- .../pack/model/special/HeadSpecialModel.java | 11 +++++--- .../model/special/ShulkerBoxSpecialModel.java | 11 +++++--- gradle.properties | 2 +- 9 files changed, 47 insertions(+), 16 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index ff18b0826..d7240fa55 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -179,6 +179,8 @@ warning.config.item.model.select.case.missing_model: "Issue found in fil warning.config.item.model.select.block_state.missing_property: "Issue found in file - The item '' is missing the required 'block-state-property' argument for property 'minecraft:block_state'." warning.config.item.model.select.local_time.missing_pattern: "Issue found in file - The item '' is missing the required 'pattern' argument for property 'minecraft:local_time'." warning.config.item.model.special.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for model 'minecraft:special'." +warning.config.item.model.special.missing_path: "Issue found in file - The item '' is missing the required 'path' argument for model 'minecraft:special'." +warning.config.item.model.special.invalid_path: "Issue found in file - The item '' has an invalid 'path' argument '' for model 'minecraft:special' which contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.item.model.special.invalid_type: "Issue found in file - The item '' is using an invalid type '' for model 'minecraft:special'." warning.config.item.model.special.banner.missing_color: "Issue found in file - The item '' is missing the required 'color' argument for special model 'minecraft:banner'." warning.config.item.model.special.bed.missing_texture: "Issue found in file - The item '' is missing the required 'texture' argument for special model 'minecraft:bed'." @@ -189,7 +191,6 @@ warning.config.item.model.special.chest.invalid_openness: "Issue found i warning.config.item.model.special.shulker_box.missing_texture: "Issue found in file - The item '' is missing the required 'texture' argument for special model 'minecraft:shulker_box'." warning.config.item.model.special.shulker_box.invalid_openness: "Issue found in file - The item '' is using an invalid 'openness' value '' for special model 'minecraft:shulker_box'. Valid range '0~1.'" warning.config.item.model.special.head.missing_kind: "Issue found in file - The item '' is missing the required 'kind' argument for special model 'minecraft:head'." -warning.config.item.model.special.head.missing_texture: "Issue found in file - The item '' is missing the required 'texture' argument for special model 'minecraft:head'." warning.config.block.duplicate: "Issue found in file - Duplicated block ''. Please check if there is the same configuration in other files." warning.config.block.missing_state: "Issue found in file - The block '' is missing the required 'state' argument." warning.config.block.state.property.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for property ''." diff --git a/bukkit/loader/src/main/resources/translations/tr.yml b/bukkit/loader/src/main/resources/translations/tr.yml index def783519..7c1c475b5 100644 --- a/bukkit/loader/src/main/resources/translations/tr.yml +++ b/bukkit/loader/src/main/resources/translations/tr.yml @@ -167,7 +167,6 @@ warning.config.item.model.special.chest.invalid_openness: " dosya warning.config.item.model.special.shulker_box.missing_texture: " dosyasında sorun bulundu - '' eşyası, 'minecraft:shulker_box' özel modeli için gerekli 'texture' argümanı eksik." warning.config.item.model.special.shulker_box.invalid_openness: " dosyasında sorun bulundu - '' eşyası, 'minecraft:shulker_box' özel modeli için geçersiz bir 'openness' değeri '' kullanıyor. Geçerli aralık '0~1.'" warning.config.item.model.special.head.missing_kind: " dosyasında sorun bulundu - '' eşyası, 'minecraft:head' özel modeli için gerekli 'kind' argümanı eksik." -warning.config.item.model.special.head.missing_texture: " dosyasında sorun bulundu - '' eşyası, 'minecraft:head' özel modeli için gerekli 'texture' argümanı eksik." warning.config.block.duplicate: " dosyasında sorun bulundu - Yinelenen blok ''. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin." warning.config.block.missing_state: " dosyasında sorun bulundu - '' bloğu gerekli 'state' argümanı eksik." warning.config.block.state.property.missing_type: " dosyasında sorun bulundu - '' bloğu, '' özelliği için gerekli 'type' argümanı eksik." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index d2e6ed5f9..2429e0ff3 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -179,6 +179,8 @@ warning.config.item.model.select.case.missing_model: "在文件 warning.config.item.model.select.block_state.missing_property: "在文件 发现问题 - 物品 '' 的 'minecraft:block_state' 属性缺少必需的 'block-state-property' 参数" warning.config.item.model.select.local_time.missing_pattern: "在文件 发现问题 - 物品 '' 的 'minecraft:local_time' 属性缺少必需的 'pattern' 参数" warning.config.item.model.special.missing_type: "在文件 发现问题 - 物品 '' 的 'minecraft:special' 模型缺少必需的 'type' 参数" +warning.config.item.model.special.missing_path: "在文件 发现问题 - 物品 '' 的 'minecraft:special' 模型缺少必需的模型 'path' 参数" +warning.config.item.model.special.invalid_path: "在文件 发现问题 - 物品 '' 的 'minecraft:special' 模型路径 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.item.model.special.invalid_type: "在文件 发现问题 - 物品 '' 的 'minecraft:special' 模型使用了无效类型 ''" warning.config.item.model.special.banner.missing_color: "在文件 发现问题 - 物品 '' 的 'minecraft:banner' 特殊模型缺少必需的 'color' 参数" warning.config.item.model.special.bed.missing_texture: "在文件 发现问题 - 物品 '' 的 'minecraft:bed' 特殊模型缺少必需的 'texture' 参数" @@ -189,7 +191,6 @@ warning.config.item.model.special.chest.invalid_openness: "在文件 在文件 发现问题 - 物品 '' 的 'minecraft:shulker_box' 特殊模型缺少必需的 'texture' 参数" warning.config.item.model.special.shulker_box.invalid_openness: "在文件 发现问题 - 物品 '' 的 'minecraft:shulker_box' 特殊模型使用了无效的 'openness' 值 '' 有效范围应为 0~1" warning.config.item.model.special.head.missing_kind: "在文件 发现问题 - 物品 '' 的 'minecraft:head' 特殊模型缺少必需的 'kind' 参数" -warning.config.item.model.special.head.missing_texture: "在文件 发现问题 - 物品 '' 的 'minecraft:head' 特殊模型缺少必需的 'texture' 参数" warning.config.block.duplicate: "在文件 发现问题 - 重复的方块 '' 请检查其他文件中是否存在相同配置" warning.config.block.missing_state: "在文件 发现问题 - 方块 '' 缺少必需的 'state' 参数" warning.config.block.state.property.missing_type: "在文件 发现问题 - 方块 '' 的属性 '' 缺少必需的 'type' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 149f335f5..853271e93 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -39,7 +39,7 @@ public abstract class BukkitItemFactory> extend case "1.21.4" -> { return new ComponentItemFactory1_21_4(plugin); } - case "1.21.5", "1.22", "1.22.1" -> { + case "1.21.5", "1.21.6", "1.22", "1.22.1" -> { return new ComponentItemFactory1_21_5(plugin); } default -> throw new IllegalStateException("Unsupported server version: " + plugin.serverVersion()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java index 99f125240..ccfa2e026 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java @@ -1,11 +1,15 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.special.SpecialModel; import net.momirealms.craftengine.core.pack.model.special.SpecialModels; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; @@ -15,10 +19,12 @@ public class SpecialItemModel implements ItemModel { public static final Factory FACTORY = new Factory(); private final SpecialModel specialModel; private final String base; + private final ModelGeneration modelGeneration; - public SpecialItemModel(SpecialModel specialModel, String base) { + public SpecialItemModel(SpecialModel specialModel, String base, @Nullable ModelGeneration generation) { this.specialModel = specialModel; this.base = base; + this.modelGeneration = generation; } public SpecialModel specialModel() { @@ -45,16 +51,28 @@ public class SpecialItemModel implements ItemModel { @Override public List modelsToGenerate() { - return List.of(); + if (this.modelGeneration == null) { + return List.of(); + } else { + return List.of(this.modelGeneration); + } } public static class Factory implements ItemModelFactory { @Override public ItemModel create(Map arguments) { - String base = Objects.requireNonNull(arguments.get("base")).toString(); + String base = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "base", "path"), "warning.config.item.model.special.missing_path"); + if (!ResourceLocation.isValid(base)) { + throw new LocalizedResourceConfigException("warning.config.item.model.special.invalid_path", base); + } + Map generation = MiscUtils.castToMap(arguments.get("generation"), true); + ModelGeneration modelGeneration = null; + if (generation != null) { + modelGeneration = new ModelGeneration(Key.of(base), generation); + } Map model = MiscUtils.castToMap(arguments.get("model"), false); - return new SpecialItemModel(SpecialModels.fromMap(model), base); + return new SpecialItemModel(SpecialModels.fromMap(model), base, modelGeneration); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ChestSpecialModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ChestSpecialModel.java index 31aaf4563..a4cdce121 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ChestSpecialModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ChestSpecialModel.java @@ -27,7 +27,9 @@ public class ChestSpecialModel implements SpecialModel { JsonObject json = new JsonObject(); json.addProperty("type", type().toString()); json.addProperty("texture", texture); - json.addProperty("openness", openness); + if (openness > 0) { + json.addProperty("openness", openness); + } return json; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/HeadSpecialModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/HeadSpecialModel.java index 6f1cf530c..7ee58315d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/HeadSpecialModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/HeadSpecialModel.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; +import java.util.Optional; public class HeadSpecialModel implements SpecialModel { public static final Factory FACTORY = new Factory(); @@ -28,8 +29,12 @@ public class HeadSpecialModel implements SpecialModel { JsonObject json = new JsonObject(); json.addProperty("type", type().toString()); json.addProperty("kind", kind); - json.addProperty("texture", texture); - json.addProperty("animation", animation); + if (texture != null) { + json.addProperty("texture", texture); + } + if (animation != 0) { + json.addProperty("animation", animation); + } return json; } @@ -38,7 +43,7 @@ public class HeadSpecialModel implements SpecialModel { @Override public SpecialModel create(Map arguments) { String kind = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("kind"), "warning.config.item.model.special.head.missing_kind"); - String texture = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("texture"), "warning.config.item.model.special.head.missing_texture"); + String texture = Optional.ofNullable(arguments.get("texture")).map(String::valueOf).orElse(null); int animation = ResourceConfigUtils.getAsInt(arguments.getOrDefault("animation", 0), "animation"); return new HeadSpecialModel(kind, texture, animation); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java index 0eaf640a6..2ba8f374c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java @@ -5,9 +5,12 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; +import java.awt.desktop.OpenFilesEvent; import java.util.Locale; import java.util.Map; +import java.util.Optional; public class ShulkerBoxSpecialModel implements SpecialModel { public static final Factory FACTORY = new Factory(); @@ -15,7 +18,7 @@ public class ShulkerBoxSpecialModel implements SpecialModel { private final float openness; private final Direction orientation; - public ShulkerBoxSpecialModel(String texture, float openness, Direction orientation) { + public ShulkerBoxSpecialModel(String texture, float openness, @Nullable Direction orientation) { this.texture = texture; this.openness = openness; this.orientation = orientation; @@ -31,8 +34,10 @@ public class ShulkerBoxSpecialModel implements SpecialModel { JsonObject json = new JsonObject(); json.addProperty("type", type().toString()); json.addProperty("texture", texture); + if (orientation != null) { + json.addProperty("orientation", orientation.name().toLowerCase(Locale.ENGLISH)); + } json.addProperty("openness", openness); - json.addProperty("orientation", orientation.name().toLowerCase(Locale.ENGLISH)); return json; } @@ -42,7 +47,7 @@ public class ShulkerBoxSpecialModel implements SpecialModel { public SpecialModel create(Map arguments) { float openness = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("openness", 0), "openness"); String texture = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("texture"), "warning.config.item.model.special.shulker_box.missing_texture"); - Direction orientation = Direction.valueOf(arguments.getOrDefault("orientation", "down").toString().toUpperCase(Locale.ENGLISH)); + Direction orientation = Optional.ofNullable(arguments.get("orientation")).map(String::valueOf).map(String::toUpperCase).map(Direction::valueOf).orElse(null); if (openness > 1 || openness < 0) { throw new LocalizedResourceConfigException("warning.config.item.model.special.shulker_box.invalid_openness", String.valueOf(openness)); } diff --git a/gradle.properties b/gradle.properties index 978455b6b..c7950e2ef 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.53.2 +project_version=0.0.53.3 config_version=32 lang_version=12 project_group=net.momirealms From 81cf2055e40394dea1bf76b59bdd1c26fdd74aa7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 9 May 2025 02:34:23 +0800 Subject: [PATCH 15/73] =?UTF-8?q?=E4=B8=BA=E5=AE=B6=E5=85=B7=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E6=8E=89=E8=90=BD=E7=89=A9?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/furniture.yml | 3 +++ .../bukkit/api/CraftEngineFurniture.java | 2 +- .../entity/furniture/BukkitFurnitureManager.java | 8 ++++++-- .../bukkit/entity/furniture/LoadedFurniture.java | 15 +++++++++++++-- .../core/entity/furniture/CustomFurniture.java | 4 +++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml b/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml index 05578bdbc..e8eb30a91 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml @@ -17,6 +17,7 @@ items: place: minecraft:block.bamboo_wood.place placement: ground: + loot-spawn-offset: 0.5,0.5,0 rules: # ANY / FOUR / EIGHT / SIXTEEN / NORTH / EAST / WEST / SOUTH rotation: FOUR @@ -61,6 +62,7 @@ items: place: minecraft:block.lantern.place placement: ground: + loot-spawn-offset: 0,0.2,0 rules: rotation: ANY alignment: QUARTER @@ -111,6 +113,7 @@ items: place: minecraft:block.bamboo_wood.place placement: ground: + loot-spawn-offset: 0,0.4,0 rules: rotation: ANY alignment: ANY diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 134fda9a6..d611eec59 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -263,7 +263,7 @@ public final class CraftEngineFurniture { @Nullable net.momirealms.craftengine.core.entity.player.Player player, boolean dropLoot, boolean playSound) { - Location location = loadedFurniture.location(); + Location location = loadedFurniture.dropLocation(); loadedFurniture.destroy(); LootTable lootTable = (LootTable) loadedFurniture.config().lootTable(); Vec3d vec3d = LocationUtils.toVec3d(location); 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 faad973b1..120430faa 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 @@ -124,6 +124,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); Map placementArguments = MiscUtils.castToMap(entry.getValue(), true); + Optional optionalLootSpawnOffset = Optional.ofNullable(placementArguments.get("loot-spawn-offset")).map(it -> MiscUtils.getAsVector3f(it, "loot-spawn-offset")); + // furniture display elements List elements = new ArrayList<>(); List> elementConfigs = (List>) placementArguments.getOrDefault("elements", List.of()); @@ -178,7 +180,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { hitboxes.toArray(new HitBox[0]), rotationRule, alignmentRule, - externalModel + externalModel, + optionalLootSpawnOffset )); } else { placements.put(anchorType, new CustomFurniture.Placement( @@ -186,7 +189,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { hitboxes.toArray(new HitBox[0]), RotationRule.ANY, AlignmentRule.CENTER, - externalModel + externalModel, + optionalLootSpawnOffset )); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 40505ab8d..ac8ba908a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -75,9 +75,9 @@ public class LoadedFurniture implements Furniture { } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id, e); } - hasExternalModel = true; + this.hasExternalModel = true; } else { - hasExternalModel = false; + this.hasExternalModel = false; } float yaw = this.location.getYaw(); @@ -176,6 +176,17 @@ public class LoadedFurniture implements Furniture { return baseEntity().isValid(); } + @NotNull + public Location dropLocation() { + Optional dropOffset = config().getPlacement(this.anchorType).dropOffset(); + if (dropOffset.isEmpty()) { + return location(); + } + Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); + Vector3f offset = conjugated.transform(new Vector3f(dropOffset.get())); + return new Location(this.location.getWorld(), this.location.getX() + offset.x, this.location.getY() + offset.y, this.location.getZ() - offset.z); + } + @Override public void destroy() { if (!isValid()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index 1b8679ae6..cbf5f12c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; import java.util.EnumMap; import java.util.Optional; @@ -60,6 +61,7 @@ public class CustomFurniture { HitBox[] hitBoxes, RotationRule rotationRule, AlignmentRule alignmentRule, - Optional externalModel) { + Optional externalModel, + Optional dropOffset) { } } From d6a081706932c34938b60c62a1541645563cc7b7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 9 May 2025 03:07:13 +0800 Subject: [PATCH 16/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=92=8Crel=E5=8F=98=E9=87=8F=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 5 ++ .../papi/PlaceholderAPIUtils.java | 5 ++ .../advancement/BukkitAdvancementManager.java | 6 +- .../bukkit/block/BukkitBlockManager.java | 6 +- .../furniture/BukkitFurnitureManager.java | 6 +- .../bukkit/item/BukkitItemManager.java | 6 +- .../bukkit/loot/BukkitVanillaLootManager.java | 6 +- .../core/advancement/AdvancementManager.java | 4 +- .../craftengine/core/block/BlockManager.java | 4 +- .../entity/furniture/FurnitureManager.java | 4 +- .../core/font/AbstractFontManager.java | 10 ++-- .../craftengine/core/font/FontManager.java | 4 +- .../craftengine/core/item/ItemManager.java | 4 +- .../item/recipe/AbstractRecipeManager.java | 6 +- .../core/item/recipe/RecipeManager.java | 4 +- .../core/loot/VanillaLootManager.java | 4 +- .../core/pack/AbstractPackManager.java | 18 +++--- .../core/pack/LoadingSequence.java | 27 ++++----- .../craftengine/core/pack/PackManager.java | 10 ++-- .../core/plugin/CompatibilityManager.java | 2 + .../craftengine/core/plugin/CraftEngine.java | 12 ++++ .../craftengine/core/plugin/Plugin.java | 3 + ...igSectionParser.java => ConfigParser.java} | 13 +++-- .../config/template/TemplateManager.java | 9 +-- .../config/template/TemplateManagerImpl.java | 23 +++----- .../plugin/context/AbstractCommonContext.java | 2 +- .../plugin/context/GlobalVariableManager.java | 57 +++++++++++++++++++ .../plugin/context/PlayerOptionalContext.java | 7 ++- .../core/plugin/context/ViewerContext.java | 16 ++++-- .../gui/category/ItemBrowserManager.java | 4 +- .../gui/category/ItemBrowserManagerImpl.java | 6 +- .../plugin/locale/TranslationManager.java | 4 +- .../plugin/locale/TranslationManagerImpl.java | 10 ++-- .../text/minimessage/GlobalVariableTag.java | 38 +++++++++++++ .../minimessage/RelationalPlaceholderTag.java | 40 +++++++++++++ .../core/sound/AbstractSoundManager.java | 10 ++-- .../craftengine/core/sound/SoundManager.java | 4 +- 37 files changed, 285 insertions(+), 114 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/plugin/config/{ConfigSectionParser.java => ConfigParser.java} (52%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index 4de975ecd..c4888be8c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -192,6 +192,11 @@ public class BukkitCompatibilityManager implements CompatibilityManager { return PlaceholderAPIUtils.parse((org.bukkit.entity.Player) player.platformPlayer(), text); } + @Override + public String parse(Player player1, Player player2, String text) { + return PlaceholderAPIUtils.parse((org.bukkit.entity.Player) player1.platformPlayer(), (org.bukkit.entity.Player) player2.platformPlayer(), text); + } + @Override public int getPlayerProtocolVersion(UUID uuid) { return ViaVersionUtils.getPlayerProtocolVersion(uuid); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java index 824236dda..e96cb46dc 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.compatibility.papi; import me.clip.placeholderapi.PlaceholderAPI; import net.momirealms.craftengine.core.plugin.CraftEngine; import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; public class PlaceholderAPIUtils { @@ -12,6 +13,10 @@ public class PlaceholderAPIUtils { return PlaceholderAPI.setPlaceholders(player, text); } + public static String parse(Player player1, Player player2, String text) { + return PlaceholderAPI.setRelationalPlaceholders(player1, player2, text); + } + public static void registerExpansions(CraftEngine plugin) { new ImageExpansion(plugin).register(); new ShiftExpansion(plugin).register(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java index 74e2a5916..8df8c971d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.core.advancement.AbstractAdvancementManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; @@ -31,11 +31,11 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.advancementParser; } - public class AdvancementParser implements ConfigSectionParser { + public class AdvancementParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"advancements", "advancement"}; @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 6142cbed6..3f6762964 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -193,7 +193,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.blockParser; } @@ -314,7 +314,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - public class BlockParser implements ConfigSectionParser { + public class BlockParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"blocks", "block"}; @Override 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 120430faa..4b79032ed 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 @@ -11,7 +11,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; @@ -86,11 +86,11 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.furnitureParser; } - public class FurnitureParser implements ConfigSectionParser { + public class FurnitureParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; @Override 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 9296dd4c5..9d72cbf8f 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 @@ -27,7 +27,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -164,7 +164,7 @@ public class BukkitItemManager extends AbstractItemManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.itemParser; } @@ -224,7 +224,7 @@ public class BukkitItemManager extends AbstractItemManager { return wrapped.id(); } - public class ItemParser implements ConfigSectionParser { + public class ItemParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index f994c121b..5875827ee 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -12,7 +12,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.VanillaLoot; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -87,11 +87,11 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.vanillaLootParser; } - public class VanillaLootParser implements ConfigSectionParser { + public class VanillaLootParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementManager.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementManager.java index 0d2b8a2b0..b4a13703b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementManager.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.core.advancement; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; public interface AdvancementManager extends Manageable { - ConfigSectionParser parser(); + ConfigParser parser(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 125f42018..8cbeb5a5a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -4,7 +4,7 @@ import com.google.gson.JsonElement; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; @@ -14,7 +14,7 @@ import java.util.Optional; public interface BlockManager extends Manageable, ModelGenerator { - ConfigSectionParser parser(); + ConfigParser parser(); Collection modelsToGenerate(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index d2692164d..2655d6804 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; @@ -15,7 +15,7 @@ import java.util.Optional; public interface FurnitureManager extends Manageable { String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; - ConfigSectionParser parser(); + ConfigParser parser(); void initSuggestions(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index aa7a7797e..6cd120eb1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -75,8 +75,8 @@ public abstract class AbstractFontManager implements FontManager { } @Override - public ConfigSectionParser[] parsers() { - return new ConfigSectionParser[] {this.imageParser, this.emojiParser}; + public ConfigParser[] parsers() { + return new ConfigParser[] {this.imageParser, this.emojiParser}; } @Override @@ -339,7 +339,7 @@ public abstract class AbstractFontManager implements FontManager { return this.fonts.computeIfAbsent(key, Font::new); } - public class EmojiParser implements ConfigSectionParser { + public class EmojiParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; @Override @@ -400,7 +400,7 @@ public abstract class AbstractFontManager implements FontManager { } } - public class ImageParser implements ConfigSectionParser { + public class ImageParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index 95d2251d4..307350eea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.FormatUtils; @@ -45,7 +45,7 @@ public interface FontManager extends Manageable { IllegalCharacterProcessResult processIllegalCharacters(String raw, char replacement); - ConfigSectionParser[] parsers(); + ConfigParser[] parsers(); default EmojiTextProcessResult replaceMiniMessageEmoji(@NotNull String miniMessage, @Nullable Player player) { return replaceMiniMessageEmoji(miniMessage, player, Config.maxEmojisPerParse()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index f3ed35781..c02f1aa54 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.pack.model.ItemModel; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; @@ -17,7 +17,7 @@ import java.util.*; public interface ItemManager extends Manageable, ModelGenerator { - ConfigSectionParser parser(); + ConfigParser parser(); Map> legacyItemOverrides(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index 7220614c4..f84e496ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; @@ -35,7 +35,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.recipeParser; } @@ -140,7 +140,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { } } - public class RecipeParser implements ConfigSectionParser { + public class RecipeParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index eb59f67ed..c1fdcdbc3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -11,7 +11,7 @@ import java.util.Optional; public interface RecipeManager extends Manageable { - ConfigSectionParser parser(); + ConfigParser parser(); boolean isDataPackRecipe(Key key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index c4fabdf8d..65ece069d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -1,14 +1,14 @@ package net.momirealms.craftengine.core.loot; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import java.util.Optional; public interface VanillaLootManager extends Manageable { - ConfigSectionParser parser(); + ConfigParser parser(); Optional getBlockLoot(int blockState); 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 b582cb7d9..cfbbf3810 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 @@ -19,7 +19,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.pack.obfuscation.ObfA; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; import net.momirealms.craftengine.core.plugin.locale.I18NData; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; @@ -70,8 +70,8 @@ public abstract class AbstractPackManager implements PackManager { private final CraftEngine plugin; private final BiConsumer eventDispatcher; private final Map loadedPacks = new HashMap<>(); - private final Map sectionParsers = new HashMap<>(); - private final TreeMap> cachedConfigs = new TreeMap<>(); + private final Map sectionParsers = new HashMap<>(); + private final TreeMap> cachedConfigs = new TreeMap<>(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; @@ -211,7 +211,7 @@ public abstract class AbstractPackManager implements PackManager { } @Override - public boolean registerConfigSectionParser(ConfigSectionParser parser) { + public boolean registerConfigSectionParser(ConfigParser parser) { for (String id : parser.sectionId()) { if (this.sectionParsers.containsKey(id)) return false; } @@ -404,7 +404,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); } - private void loadResourceConfigs(Predicate predicate) { + private void loadResourceConfigs(Predicate predicate) { long o1 = System.nanoTime(); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; @@ -435,8 +435,8 @@ public abstract class AbstractPackManager implements PackManager { } long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); - for (Map.Entry> entry : this.cachedConfigs.entrySet()) { - ConfigSectionParser parser = entry.getKey(); + for (Map.Entry> entry : this.cachedConfigs.entrySet()) { + ConfigParser parser = entry.getKey(); long t1 = System.nanoTime(); for (CachedConfig cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { @@ -444,8 +444,8 @@ public abstract class AbstractPackManager implements PackManager { try { Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); try { - if (parser.isTemplate()) { - this.plugin.templateManager().addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue()); + if (parser.supportsParsingObject()) { + parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); } else if (predicate.test(parser)) { if (configEntry.getValue() instanceof Map configSection0) { Map configSection1 = castToMap(configSection0, false); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java index 104508c8c..b684aa54f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java @@ -2,17 +2,18 @@ package net.momirealms.craftengine.core.pack; public class LoadingSequence { public static final int TEMPLATE = 0; - public static final int LANG = 10; - public static final int TRANSLATION = 20; - public static final int BLOCK = 30; - public static final int ITEM = 40; - public static final int FURNITURE = 50; - public static final int IMAGE = 60; - public static final int RECIPE = 70; - public static final int CATEGORY = 80; - public static final int SOUND = 90; - public static final int JUKEBOX_SONG = 100; - public static final int VANILLA_LOOTS = 110; - public static final int EMOJI = 120; - public static final int ADVANCEMENT = 130; + public static final int GLOBAL_VAR = 10; + public static final int LANG = 20; + public static final int TRANSLATION = 30; + public static final int BLOCK = 40; + public static final int ITEM = 50; + public static final int FURNITURE = 60; + public static final int IMAGE = 70; + public static final int RECIPE = 80; + public static final int CATEGORY = 90; + public static final int SOUND = 100; + public static final int JUKEBOX_SONG = 110; + public static final int VANILLA_LOOTS = 120; + public static final int EMOJI = 130; + public static final int ADVANCEMENT = 140; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 0734ded69..44641827a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.pack; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; @@ -16,17 +16,17 @@ public interface PackManager extends Manageable { @NotNull Collection loadedPacks(); - boolean registerConfigSectionParser(ConfigSectionParser parser); + boolean registerConfigSectionParser(ConfigParser parser); - default void registerConfigSectionParsers(ConfigSectionParser[] parsers) { - for (ConfigSectionParser parser : parsers) { + default void registerConfigSectionParsers(ConfigParser[] parsers) { + for (ConfigParser parser : parsers) { registerConfigSectionParser(parser); } } boolean unregisterConfigSectionParser(String id); - default void unregisterConfigSectionParser(ConfigSectionParser parser) { + default void unregisterConfigSectionParser(ConfigParser parser) { for (String id : parser.sectionId()) { unregisterConfigSectionParser(id); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java index b6f1d0794..7749be015 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java @@ -27,5 +27,7 @@ public interface CompatibilityManager { String parse(Player player, String text); + String parse(Player player1, Player player2, String text); + int getPlayerProtocolVersion(UUID uuid); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 64fa38f73..51e975b79 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; import net.momirealms.craftengine.core.plugin.config.template.TemplateManagerImpl; +import net.momirealms.craftengine.core.plugin.context.GlobalVariableManager; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; import net.momirealms.craftengine.core.plugin.dependency.Dependency; import net.momirealms.craftengine.core.plugin.dependency.DependencyManager; @@ -68,6 +69,7 @@ public abstract class CraftEngine implements Plugin { protected VanillaLootManager vanillaLootManager; protected AdvancementManager advancementManager; protected CompatibilityManager compatibilityManager; + protected GlobalVariableManager globalVariableManager; private final Consumer reloadEventDispatcher; private boolean isReloading; @@ -133,6 +135,7 @@ public abstract class CraftEngine implements Plugin { this.translationManager.reload(); // clear the outdated cache by reloading the managers this.templateManager.reload(); + this.globalVariableManager.reload(); this.furnitureManager.reload(); this.fontManager.reload(); this.itemManager.reload(); @@ -198,6 +201,7 @@ public abstract class CraftEngine implements Plugin { this.isInitializing = true; this.networkManager.init(); this.templateManager = new TemplateManagerImpl(); + this.globalVariableManager = new GlobalVariableManager(); this.itemBrowserManager = new ItemBrowserManagerImpl(this); this.commandManager.registerDefaultFeatures(); // delay the reload so other plugins can register some custom parsers @@ -245,6 +249,7 @@ public abstract class CraftEngine implements Plugin { if (this.soundManager != null) this.soundManager.disable(); if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); if (this.translationManager != null) this.translationManager.disable(); + if (this.globalVariableManager != null) this.globalVariableManager.disable(); if (this.scheduler != null) this.scheduler.shutdownScheduler(); if (this.scheduler != null) this.scheduler.shutdownExecutor(); if (this.commandManager != null) this.commandManager.unregisterFeatures(); @@ -255,6 +260,8 @@ public abstract class CraftEngine implements Plugin { protected void registerDefaultParsers() { // register template parser this.packManager.registerConfigSectionParser(this.templateManager.parser()); + // register global variables parser + this.packManager.registerConfigSectionParser(this.globalVariableManager.parser()); // register font parser this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); // register item parser @@ -430,6 +437,11 @@ public abstract class CraftEngine implements Plugin { return compatibilityManager; } + @Override + public GlobalVariableManager globalVariableManager() { + return globalVariableManager; + } + @Override public Platform platform() { return platform; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index 37ef07865..1dde1374e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; +import net.momirealms.craftengine.core.plugin.context.GlobalVariableManager; import net.momirealms.craftengine.core.plugin.dependency.DependencyManager; import net.momirealms.craftengine.core.plugin.gui.GuiManager; import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManager; @@ -91,5 +92,7 @@ public interface Plugin { CompatibilityManager compatibilityManager(); + GlobalVariableManager globalVariableManager(); + Platform platform(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java index 0c7f94f94..4d6fae451 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java @@ -8,20 +8,25 @@ import org.jetbrains.annotations.NotNull; import java.nio.file.Path; import java.util.Map; -public interface ConfigSectionParser extends Comparable { +public interface ConfigParser extends Comparable { String[] sectionId(); - void parseSection(Pack pack, Path path, Key id, Map section) throws LocalizedException; + default void parseSection(Pack pack, Path path, Key id, Map section) throws LocalizedException { + this.parseObject(pack, path, id, section); + } + + default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException { + } int loadingSequence(); - default boolean isTemplate() { + default boolean supportsParsingObject() { return false; } @Override - default int compareTo(@NotNull ConfigSectionParser another) { + default int compareTo(@NotNull ConfigParser another) { return Integer.compare(loadingSequence(), another.loadingSequence()); } } 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 b6b2b00be..01f24d80e 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 @@ -1,11 +1,8 @@ package net.momirealms.craftengine.core.plugin.config.template; -import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import java.nio.file.Path; import java.util.Map; import java.util.regex.Pattern; @@ -17,9 +14,7 @@ public interface TemplateManager extends Manageable { String OVERRIDES = "overrides"; String ARGUMENTS = "arguments"; - ConfigSectionParser parser(); - - void addTemplate(Pack pack, Path path, Key id, Object obj); + ConfigParser parser(); Map applyTemplates(Map input); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 080dfa9ba..8eda9774e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; @@ -24,7 +24,7 @@ public class TemplateManagerImpl implements TemplateManager { this.templateParser = new TemplateParser(); } - public class TemplateParser implements ConfigSectionParser { + public class TemplateParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; @Override @@ -38,13 +38,16 @@ public class TemplateManagerImpl implements TemplateManager { } @Override - public boolean isTemplate() { + public boolean supportsParsingObject() { return true; } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - addTemplate(pack, path, id, section); + public void parseObject(Pack pack, Path path, Key id, Object obj) { + if (templates.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.template.duplicate", path.toString(), id.toString()); + } + templates.put(id, obj); } } @@ -54,18 +57,10 @@ public class TemplateManagerImpl implements TemplateManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.templateParser; } - @Override - public void addTemplate(Pack pack, Path path, Key id, Object obj) { - if (this.templates.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.template.duplicate", path.toString(), id.toString()); - } - this.templates.put(id, obj); - } - @Override public Map applyTemplates(Map input) { Objects.requireNonNull(input, "Input must not be null"); 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 4717ae0e0..1863c0ab8 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 @@ -24,7 +24,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 PlaceholderTag(null), new ExpressionTag(this), new GlobalVariableTag(this)}; } return this.tagResolvers; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java new file mode 100644 index 000000000..5c29100a9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java @@ -0,0 +1,57 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.Manageable; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +public class GlobalVariableManager implements Manageable { + private final Map globalVariables = new HashMap<>(); + private final GlobalVariableParser parser = new GlobalVariableParser(); + + @Nullable + public String get(final String key) { + return this.globalVariables.get(key); + } + + @Override + public void unload() { + this.globalVariables.clear(); + } + + public ConfigParser parser() { + return this.parser; + } + + public class GlobalVariableParser implements ConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"global-variables", "global-variable"}; + + @Override + public int loadingSequence() { + return LoadingSequence.GLOBAL_VAR; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public boolean supportsParsingObject() { + return true; + } + + @Override + public void parseObject(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Object object) throws LocalizedException { + if (object != null) { + globalVariables.put(id.value(), object.toString()); + } + } + } +} 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 e471cc51a..ac63f07c9 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 @@ -48,11 +48,16 @@ public class PlayerOptionalContext extends AbstractAdditionalParameterContext im return this.player; } + public boolean isPlayerPresent() { + return this.player != null; + } + @Override @NotNull public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { - this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), new NamedArgumentTag(this), new ExpressionTag(this)}; + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), 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 4591d242d..cc4f2d761 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 @@ -57,10 +57,18 @@ public class ViewerContext implements RelationalContext { if (this.owner instanceof PlayerOptionalContext context) { optionalOwner = context.player(); } - this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, - new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), - new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), - new I18NTag(this), new ExpressionTag(this)}; + if (optionalOwner != null && this.viewer.player != null) { + this.tagResolvers = new TagResolver[]{new RelationalPlaceholderTag(optionalOwner, this.viewer.player), + ShiftTag.INSTANCE, ImageTag.INSTANCE, + new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + 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 NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), + new I18NTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; + } } return this.tagResolvers; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index e9de45dab..9d6b9732b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.gui.Gui; import net.momirealms.craftengine.core.util.Key; @@ -19,7 +19,7 @@ public interface ItemBrowserManager extends Manageable { int MAX_RECIPE_DEPTH = 16; String GET_ITEM_PERMISSION = "craftengine.browser.get_item"; - ConfigSectionParser parser(); + ConfigParser parser(); void addExternalCategoryMember(Key item, List category); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 9d6f17d16..024b294df 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.gui.*; @@ -68,7 +68,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } @Override - public ConfigSectionParser parser() { + public ConfigParser parser() { return this.categoryParser; } @@ -93,7 +93,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return Optional.ofNullable(this.byId.get(key)); } - public class CategoryParser implements ConfigSectionParser { + public class CategoryParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index f8bab04f3..d4ec4c773 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.Translator; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -44,7 +44,7 @@ public interface TranslationManager extends Manageable { return TranslationManagerImpl.instance; } - ConfigSectionParser[] parsers(); + ConfigParser[] parsers(); default String miniMessageTranslation(String key) { return miniMessageTranslation(key, null); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index dbbcdd70c..d73c40551 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -63,8 +63,8 @@ public class TranslationManagerImpl implements TranslationManager { } @Override - public ConfigSectionParser[] parsers() { - return new ConfigSectionParser[] {this.langParser, this.i18nParser}; + public ConfigParser[] parsers() { + return new ConfigParser[] {this.langParser, this.i18nParser}; } @Override @@ -277,7 +277,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class I18NParser implements ConfigSectionParser { + public class I18NParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; @Override @@ -308,7 +308,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class LangParser implements ConfigSectionParser { + public class LangParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java new file mode 100644 index 000000000..0a7602b0e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +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.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.AdventureHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class GlobalVariableTag implements TagResolver { + private final Context context; + + public GlobalVariableTag(Context context) { + this.context = context; + } + + @Override + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull net.kyori.adventure.text.minimessage.Context ctx) throws ParsingException { + if (!this.has(name)) { + return null; + } + String id = arguments.popOr("No argument variable id provided").toString(); + String value = CraftEngine.instance().globalVariableManager().get(id); + if (value == null) { + throw ctx.newException("Unknown variable: ", arguments); + } + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, this.context.tagResolvers())); + } + + @Override + public boolean has(@NotNull String name) { + return "global".equals(name); + } +} 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 new file mode 100644 index 000000000..07f175b6d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import net.kyori.adventure.text.minimessage.Context; +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.util.AdventureHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class RelationalPlaceholderTag implements TagResolver { + private final Player player1; + private final Player player2; + + public RelationalPlaceholderTag(@NotNull Player player1, @NotNull Player player2) { + this.player1 = player1; + this.player2 = player2; + } + + @Override + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + 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); + if (parsed.equals(placeholder)) { + parsed = arguments.popOr("No default papi value provided").toString(); + } + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(parsed)); + } + + @Override + public boolean has(@NotNull String name) { + return "rel_papi".equals(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index 789aa65d8..d75ee7ec8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; @@ -32,8 +32,8 @@ public abstract class AbstractSoundManager implements SoundManager { } @Override - public ConfigSectionParser[] parsers() { - return new ConfigSectionParser[] { this.soundParser, this.songParser }; + public ConfigParser[] parsers() { + return new ConfigParser[] { this.soundParser, this.songParser }; } @Override @@ -59,7 +59,7 @@ public abstract class AbstractSoundManager implements SoundManager { protected abstract void registerSongs(Map songs); - public class SongParser implements ConfigSectionParser { + public class SongParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "song", "songs", "jukebox", "jukebox_song"}; @Override @@ -86,7 +86,7 @@ public abstract class AbstractSoundManager implements SoundManager { } } - public class SoundParser implements ConfigSectionParser { + public class SoundParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 54450acd5..55eeb6e4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.sound; import net.momirealms.craftengine.core.plugin.Manageable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import java.util.Map; @@ -10,7 +10,7 @@ public interface SoundManager extends Manageable { boolean isVanillaSoundEvent(Key key); - ConfigSectionParser[] parsers(); + ConfigParser[] parsers(); Map sounds(); } From a705a8e8de3f1d33d2fe80f8f2a2e080ec896820 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 9 May 2025 22:39:40 +0800 Subject: [PATCH 17/73] =?UTF-8?q?=E5=A2=9E=E5=BC=BAgeneration=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/categories.yml | 4 +- .../resources/default/configuration/items.yml | 35 ++- .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../bukkit/block/BukkitBlockManager.java | 2 +- .../bukkit/item/BukkitItemManager.java | 6 + .../core/pack/AbstractPackManager.java | 2 +- .../core/pack/model/BaseItemModel.java | 2 +- .../core/pack/model/SpecialItemModel.java | 3 +- .../generation/AbstractModelGenerator.java | 9 +- .../core/pack/model/generation/GuiLight.java | 5 + .../model/generation/ModelGeneration.java | 228 +++++++++++++++--- .../model/generation/display/DisplayMeta.java | 25 ++ .../generation/display/DisplayPosition.java | 12 + .../model/special/ShulkerBoxSpecialModel.java | 1 - .../text/minimessage/GlobalVariableTag.java | 1 - 16 files changed, 295 insertions(+), 44 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/GuiLight.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayMeta.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayPosition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index 3c8d218d6..3189f43a4 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -62,4 +62,6 @@ categories: - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block - - default:ender_pearl_flower_seeds \ No newline at end of file + - default:ender_pearl_flower_seeds + - default:gui_head_size_1 + - default:gui_head_size_4 \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml index 02fa220c0..b21baa96f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml @@ -1,4 +1,37 @@ -items: +items#gui_head: + default:gui_head_size_1: + material: player_head + custom-model-data: 1000 + model: + type: minecraft:special + path: minecraft:item/custom/gui_head_size_1 + generation: + parent: minecraft:item/template_skull + gui-light: front + display: + gui: + translation: 0,8,0 + scale: 2,2,2 + model: + type: minecraft:head + kind: player + default:gui_head_size_4: + material: player_head + custom-model-data: 1001 + model: + type: minecraft:special + path: minecraft:item/custom/gui_head_size_4 + generation: + parent: minecraft:item/template_skull + gui-light: front + display: + gui: + translation: 9,7,0 + scale: 4,4,4 + model: + type: minecraft:head + kind: player +items#topaz_gears: default:topaz_rod: material: fishing_rod custom-model-data: 1000 diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index d7240fa55..3f0da67b9 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -227,6 +227,8 @@ warning.config.block.behavior.strippable.missing_stripped: "Issue found warning.config.block.event.condition.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for event condition." warning.config.block.event.condition.invalid_type: "Issue found in file - The block '' is using an invalid 'type' argument '' for event condition." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." +warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" +warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." warning.config.model.generation.texture.invalid: "Issue found in file - The config '' has a texture '' with path '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.model.generation.parent.invalid: "Issue found in file - The config '' has a parent argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 2429e0ff3..9a75a659e 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -228,6 +228,8 @@ warning.config.block.event.condition.missing_type: "在文件 - warning.config.block.event.condition.invalid_type: "在文件 - 方块 '' 使用了无效的事件条件类型 ''" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" +warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" +warning.config.model.generation.invalid_gui_light: "在文件 发现问题 - 配置项 '' 在 'generation' 区域使用了无效的GUI光照 ''. 可用GUI光照: []" warning.config.model.generation.texture.invalid: "在文件 发现问题 - 配置项 '' 的纹理 '' 路径 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.model.generation.parent.invalid: "在文件 发现问题 - 配置项 '' 的父级参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.emoji.missing_keywords: "在文件 发现问题 - 表情 '' 缺少必需的 'keywords' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 3f6762964..8bd60c4c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -537,7 +537,7 @@ public class BukkitBlockManager extends AbstractBlockManager { if (singleModelMap.containsKey("weight")) json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight")); Map generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true); if (generationMap != null) { - prepareModelGeneration(new ModelGeneration(Key.of(modelPath), generationMap)); + prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap)); } variants.add(json); } 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 9d72cbf8f..fe46abf8e 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 @@ -463,6 +463,12 @@ public class BukkitItemManager extends AbstractItemManager { baseModel.path(), customModelData )); + } else if (currentModel instanceof SpecialItemModel specialModel) { + resultList.add(new LegacyOverridesModel( + new LinkedHashMap<>(accumulatedPredicates), + specialModel.base(), + customModelData + )); } } 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 cfbbf3810..a4a02839d 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 @@ -832,7 +832,7 @@ public abstract class AbstractPackManager implements PackManager { } try (BufferedWriter writer = Files.newBufferedWriter(modelPath)) { - GsonHelper.get().toJson(generation.getJson(), writer); + GsonHelper.get().toJson(generation.get(), writer); } catch (IOException e) { plugin.logger().warn("Failed to generate model: " + modelPath.toAbsolutePath(), e); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java index 4b2609c3b..1756b6b14 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java @@ -77,7 +77,7 @@ public class BaseItemModel implements ItemModel { Map generation = MiscUtils.castToMap(arguments.get("generation"), true); ModelGeneration modelGeneration = null; if (generation != null) { - modelGeneration = new ModelGeneration(Key.of(modelPath), generation); + modelGeneration = ModelGeneration.of(Key.of(modelPath), generation); } if (arguments.containsKey("tints")) { List tints = new ArrayList<>(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java index ccfa2e026..50052ce85 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SpecialItemModel.java @@ -13,7 +13,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Objects; public class SpecialItemModel implements ItemModel { public static final Factory FACTORY = new Factory(); @@ -69,7 +68,7 @@ public class SpecialItemModel implements ItemModel { Map generation = MiscUtils.castToMap(arguments.get("generation"), true); ModelGeneration modelGeneration = null; if (generation != null) { - modelGeneration = new ModelGeneration(Key.of(base), generation); + modelGeneration = ModelGeneration.of(Key.of(base), generation); } Map model = MiscUtils.castToMap(arguments.get("model"), false); return new SpecialItemModel(SpecialModels.fromMap(model), base, modelGeneration); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java index e34e9f374..acc0d0c08 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java @@ -38,9 +38,12 @@ public abstract class AbstractModelGenerator implements ModelGenerator { if (!ResourceLocation.isValid(model.parentModelPath())) { throw new LocalizedResourceConfigException("warning.config.model.generation.parent.invalid", model.parentModelPath()); } - for (Map.Entry texture : model.texturesOverride().entrySet()) { - if (!ResourceLocation.isValid(texture.getValue())) { - throw new LocalizedResourceConfigException("warning.config.model.generation.texture.invalid", texture.getKey(), texture.getValue()); + Map textures = model.texturesOverride(); + if (textures != null) { + for (Map.Entry texture : textures.entrySet()) { + if (!ResourceLocation.isValid(texture.getValue())) { + throw new LocalizedResourceConfigException("warning.config.model.generation.texture.invalid", texture.getKey(), texture.getValue()); + } } } this.modelsToGenerate.put(model.path(), model); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/GuiLight.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/GuiLight.java new file mode 100644 index 000000000..0977aa82a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/GuiLight.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.pack.model.generation; + +public enum GuiLight { + FRONT, SIDE +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java index 086d8c6d5..883d89196 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java @@ -1,44 +1,107 @@ package net.momirealms.craftengine.core.pack.model.generation; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.pack.model.generation.display.DisplayMeta; +import net.momirealms.craftengine.core.pack.model.generation.display.DisplayPosition; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.EnumUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Supplier; -public class ModelGeneration { +public class ModelGeneration implements Supplier { + private static final Map> BUILDER_FUNCTIONS = new HashMap<>(); + static { + BUILDER_FUNCTIONS.put("textures", (b, data) -> { + Map texturesMap = MiscUtils.castToMap(data, false); + Map texturesOverride = new LinkedHashMap<>(); + for (Map.Entry entry : texturesMap.entrySet()) { + if (entry.getValue() instanceof String p) { + texturesOverride.put(entry.getKey(), p); + } + } + b.texturesOverride(texturesOverride); + }); + BUILDER_FUNCTIONS.put("display", (b, data) -> { + Map displayMap = MiscUtils.castToMap(data, false); + Map displays = new EnumMap<>(DisplayPosition.class); + for (Map.Entry entry : displayMap.entrySet()) { + try { + DisplayPosition displayPosition = DisplayPosition.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); + if (entry.getValue() instanceof Map metaMap) { + displays.put(displayPosition, DisplayMeta.fromMap(MiscUtils.castToMap(metaMap, false))); + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.model.generation.invalid_display_position", e, entry.getKey(), EnumUtils.toString(DisplayPosition.values())); + } + } + b.displays(displays); + }); + BUILDER_FUNCTIONS.put("gui-light", (b, data) -> { + String guiLightStr = String.valueOf(data); + try { + GuiLight guiLight = GuiLight.valueOf(guiLightStr.toUpperCase(Locale.ENGLISH)); + b.guiLight(guiLight); + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.model.generation.invalid_gui_light", e, guiLightStr, EnumUtils.toString(GuiLight.values())); + } + }); + BUILDER_FUNCTIONS.put("ambient-occlusion", (b, data) -> { + b.ambientOcclusion((boolean) data); + }); + BUILDER_FUNCTIONS.put("parent", (b, data) -> { + String parentModelPath = data.toString(); + b.parentModelPath(parentModelPath); + }); + } + + @NotNull private final Key path; + @NotNull private final String parentModelPath; + @Nullable private final Map texturesOverride; + @Nullable + private final Map displays; + @Nullable + private final GuiLight guiLight; + @Nullable + private final Boolean ambientOcclusion; + @Nullable + private JsonObject cachedModel; - public ModelGeneration(Key path, String parentModelPath, Map texturesOverride) { + public ModelGeneration(@NotNull Key path, + @NotNull String parentModelPath, + @Nullable Map texturesOverride, + @Nullable Map displays, + @Nullable GuiLight guiLight, + @Nullable Boolean ambientOcclusion) { this.path = path; this.parentModelPath = parentModelPath; this.texturesOverride = texturesOverride; + this.displays = displays; + this.guiLight = guiLight; + this.ambientOcclusion = ambientOcclusion; } - public ModelGeneration(Key path, Map map) { - this.path = path; - Object parent = map.get("parent"); - if (parent == null) { - throw new LocalizedResourceConfigException("warning.config.model.generation.missing_parent"); - } - this.parentModelPath = parent.toString(); - Map texturesMap = MiscUtils.castToMap(map.get("textures"), true); - if (texturesMap != null) { - this.texturesOverride = new LinkedHashMap<>(); - for (Map.Entry entry : texturesMap.entrySet()) { - if (entry.getValue() instanceof String p) { - this.texturesOverride.put(entry.getKey(), p); - } - } - } else { - this.texturesOverride = Collections.emptyMap(); + public static ModelGeneration of(Key path, Map map) { + Builder builder = builder().path(path); + for (Map.Entry entry : map.entrySet()) { + Optional.ofNullable(BUILDER_FUNCTIONS.get(entry.getKey())).ifPresent(it -> it.accept(builder, entry.getValue())); } + return builder.build(); + } + + @Nullable + public Map texturesOverride() { + return texturesOverride; } public Key path() { @@ -49,36 +112,137 @@ public class ModelGeneration { return parentModelPath; } - public Map texturesOverride() { - return texturesOverride; + @Nullable + public Map displays() { + return displays; } - public JsonObject getJson() { + @Nullable + public GuiLight guiLight() { + return guiLight; + } + + @Nullable + public Boolean ambientOcclusion() { + return ambientOcclusion; + } + + @Override + public JsonObject get() { + if (this.cachedModel == null) { + this.cachedModel = this.getCachedModel(); + } + return this.cachedModel; + } + + private JsonObject getCachedModel() { JsonObject model = new JsonObject(); - model.addProperty("parent", parentModelPath); - if (this.texturesOverride != null && !this.texturesOverride.isEmpty()) { + model.addProperty("parent", this.parentModelPath); + if (this.texturesOverride != null) { JsonObject textures = new JsonObject(); for (Map.Entry entry : this.texturesOverride.entrySet()) { textures.addProperty(entry.getKey(), entry.getValue()); } model.add("textures", textures); } + if (this.displays != null) { + JsonObject displays = new JsonObject(); + for (Map.Entry entry : this.displays.entrySet()) { + JsonObject displayMetadata = new JsonObject(); + DisplayMeta meta = entry.getValue(); + if (meta.rotation() != null) + displayMetadata.add("rotation", vectorToJsonArray(meta.rotation())); + if (meta.translation() != null) + displayMetadata.add("translation", vectorToJsonArray(meta.translation())); + if (meta.scale() != null) + displayMetadata.add("scale", vectorToJsonArray(meta.scale())); + displays.add(entry.getKey().name().toLowerCase(Locale.ENGLISH), displayMetadata); + } + model.add("display", displays); + } + if (this.guiLight != null) { + model.addProperty("gui_light", this.guiLight.name().toLowerCase(Locale.ENGLISH)); + } return model; } + private JsonArray vectorToJsonArray(Vector3f vector) { + JsonArray array = new JsonArray(); + array.add(vector.x()); + array.add(vector.y()); + array.add(vector.z()); + return array; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ModelGeneration that = (ModelGeneration) o; - return this.path.equals(that.path) && parentModelPath.equals(that.parentModelPath) && Objects.equals(texturesOverride, that.texturesOverride); + return this.path.equals(that.path) && parentModelPath.equals(that.parentModelPath) && Objects.equals(texturesOverride, that.texturesOverride) + && Objects.equals(displays, that.displays) && Objects.equals(ambientOcclusion, that.ambientOcclusion) && Objects.equals(guiLight, that.guiLight); } @Override public int hashCode() { - int result = path.hashCode(); - result = 31 * result + parentModelPath.hashCode(); - result = 31 * result + texturesOverride.hashCode(); + int result = this.path.hashCode(); + result = 31 * result + this.parentModelPath.hashCode(); return result; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Key path; + private String parentModelPath; + @Nullable + private Map texturesOverride; + @Nullable + private Map displays; + @Nullable + private GuiLight guiLight; + @Nullable + private Boolean ambientOcclusion; + + public Builder() {} + + public Builder path(Key key) { + this.path = key; + return this; + } + + public Builder parentModelPath(String parentModelPath) { + this.parentModelPath = parentModelPath; + return this; + } + + public Builder texturesOverride(Map texturesOverride) { + this.texturesOverride = texturesOverride; + return this; + } + + public Builder displays(Map displays) { + this.displays = displays; + return this; + } + + public Builder guiLight(GuiLight guiLight) { + this.guiLight = guiLight; + return this; + } + + public Builder ambientOcclusion(Boolean ambientOcclusion) { + this.ambientOcclusion = ambientOcclusion; + return this; + } + + public ModelGeneration build() { + if (this.parentModelPath == null) { + throw new LocalizedResourceConfigException("warning.config.model.generation.missing_parent"); + } + return new ModelGeneration(Objects.requireNonNull(this.path, "path should be nonnull"), this.parentModelPath, this.texturesOverride, this.displays, this.guiLight, this.ambientOcclusion); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayMeta.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayMeta.java new file mode 100644 index 000000000..31549e547 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayMeta.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.pack.model.generation.display; + +import net.momirealms.craftengine.core.util.MiscUtils; +import org.joml.Vector3f; + +import java.util.Map; + +public record DisplayMeta(Vector3f rotation, Vector3f translation, Vector3f scale) { + + public static DisplayMeta fromMap(Map map) { + Vector3f rotation = null; + if (map.containsKey("rotation")) { + rotation = MiscUtils.getAsVector3f(map.get("rotation"), "rotation"); + } + Vector3f translation = null; + if (map.containsKey("translation")) { + translation = MiscUtils.getAsVector3f(map.get("translation"), "translation"); + } + Vector3f scale = null; + if (map.containsKey("scale")) { + scale = MiscUtils.getAsVector3f(map.get("scale"), "scale"); + } + return new DisplayMeta(rotation, translation, scale); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayPosition.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayPosition.java new file mode 100644 index 000000000..0f5f30a3c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/display/DisplayPosition.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.pack.model.generation.display; + +public enum DisplayPosition { + THIRDPERSON_RIGHTHAND, + THIRDPERSON_LEFTHAND, + FIRSTPERSON_RIGHTHAND, + FIRSTPERSON_LEFTHAND, + GUI, + HEAD, + GROUND, + FIXED +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java index 2ba8f374c..917474670 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java @@ -7,7 +7,6 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.Nullable; -import java.awt.desktop.OpenFilesEvent; import java.util.Locale; import java.util.Map; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java index 0a7602b0e..257a3a72e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java @@ -6,7 +6,6 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; From 289cc5028caadc6711ad64b75b6068c50fb848e1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 10 May 2025 00:09:38 +0800 Subject: [PATCH 18/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9Btint?= =?UTF-8?q?=E5=92=8Ctexture=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generation/AbstractModelGenerator.java | 6 ++- .../core/pack/model/tint/ConstantTint.java | 4 +- .../pack/model/tint/CustomModelDataTint.java | 4 +- .../pack/model/tint/SimpleDefaultTint.java | 4 +- .../core/pack/model/tint/Tint.java | 6 +-- .../core/pack/model/tint/TintFactory.java | 41 +++++++++++++++---- gradle.properties | 2 +- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java index acc0d0c08..d62e049f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java @@ -41,8 +41,10 @@ public abstract class AbstractModelGenerator implements ModelGenerator { Map textures = model.texturesOverride(); if (textures != null) { for (Map.Entry texture : textures.entrySet()) { - if (!ResourceLocation.isValid(texture.getValue())) { - throw new LocalizedResourceConfigException("warning.config.model.generation.texture.invalid", texture.getKey(), texture.getValue()); + if (texture.getValue().charAt(0) != '#') { + if (!ResourceLocation.isValid(texture.getValue())) { + throw new LocalizedResourceConfigException("warning.config.model.generation.texture.invalid", texture.getKey(), texture.getValue()); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/ConstantTint.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/ConstantTint.java index e1b926ae6..54c6d40c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/ConstantTint.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/ConstantTint.java @@ -10,9 +10,9 @@ import java.util.Map; public class ConstantTint implements Tint { public static final Factory FACTORY = new Factory(); - private final Either> value; + private final Either> value; - public ConstantTint(Either> value) { + public ConstantTint(Either> value) { this.value = value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/CustomModelDataTint.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/CustomModelDataTint.java index c76be9f9e..0ed576384 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/CustomModelDataTint.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/CustomModelDataTint.java @@ -10,10 +10,10 @@ import java.util.Map; public class CustomModelDataTint implements Tint { public static final Factory FACTORY = new Factory(); - private final Either> value; + private final Either> value; private final int index; - public CustomModelDataTint(Either> value, int index) { + public CustomModelDataTint(Either> value, int index) { this.index = index; this.value = value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/SimpleDefaultTint.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/SimpleDefaultTint.java index a08c0daec..a543bcfe9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/SimpleDefaultTint.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/SimpleDefaultTint.java @@ -9,10 +9,10 @@ import java.util.Map; public class SimpleDefaultTint implements Tint { public static final Factory FACTORY = new Factory(); - private final Either> value; + private final Either> value; private final Key type; - public SimpleDefaultTint(Either> value, Key type) { + public SimpleDefaultTint(Either> value, Key type) { this.value = value; this.type = type; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tint.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tint.java index 364145257..b0be23502 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tint.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tint.java @@ -12,16 +12,16 @@ public interface Tint extends Supplier { Key type(); - default void applyAnyTint(JsonObject json, Either> value, String key) { + default void applyAnyTint(JsonObject json, Either> value, String key) { if (value.primary().isPresent()) { json.addProperty(key, value.primary().get()); } else { - List list = value.fallback().get(); + List list = value.fallback().get(); if (list.size() != 3) { throw new RuntimeException("Invalid tint value list size: " + list.size() + " which is expected to be 3"); } JsonArray array = new JsonArray(); - for (int i : list) { + for (float i : list) { array.add(i); } json.add(key, array); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/TintFactory.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/TintFactory.java index ee595ad49..e0fbd1947 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/TintFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/TintFactory.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.pack.model.tint; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.MiscUtils; import org.incendo.cloud.type.Either; import java.util.ArrayList; @@ -11,27 +12,51 @@ public interface TintFactory { Tint create(Map arguments); - default Either> parseTintValue(Object value) { + default Either> parseTintValue(Object value) { if (value instanceof Number i) { return Either.ofPrimary(i.intValue()); } else if (value instanceof List list) { if (list.size() == 3) { - List intList = new ArrayList<>(); - for (Object o : list) { - intList.add(Integer.parseInt(o.toString())); + List strList = MiscUtils.getAsStringList(list); + boolean hasDot = false; + for (String str : strList) { + if (str.contains(".")) { + hasDot = true; + break; + } } - return Either.ofFallback(intList); + List fList = new ArrayList<>(); + for (String str : strList) { + if (hasDot) { + fList.add(Float.parseFloat(str)); + } else { + fList.add(convertToFloat(Integer.parseInt(str))); + } + } + return Either.ofFallback(fList); } } else if (value instanceof String s) { String[] split = s.split(","); if (split.length == 3) { - List intList = new ArrayList<>(); + List fList = new ArrayList<>(); + boolean hasDot = s.contains("."); for (String string : split) { - intList.add(Integer.parseInt(string)); + if (hasDot) { + fList.add(Float.parseFloat(string)); + } else { + fList.add(convertToFloat(Integer.parseInt(string))); + } } - return Either.ofFallback(intList); + return Either.ofFallback(fList); } } throw new LocalizedResourceConfigException("warning.config.item.model.tint.invalid_value", value.toString()); } + + static float convertToFloat(int value) { + if (value < 0 || value > 255) { + throw new IllegalArgumentException("Tint value out of range: " + value + ". Allowed range is [0,255]"); + } + return value / 255.0f; + } } diff --git a/gradle.properties b/gradle.properties index c7950e2ef..ccae7e353 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.53.3 +project_version=0.0.53.4 config_version=32 lang_version=12 project_group=net.momirealms From 5cfb418eb0e0b436272d76f1e9a90506dc7d1b9c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 02:37:44 +0800 Subject: [PATCH 19/73] =?UTF-8?q?refactor(bukkit):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=89=E5=8F=89=E6=88=9F=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 13 +- .../plugin/network/PacketConsumers.java | 76 +---------- .../bukkit/util/CustomTridentUtils.java | 118 ++++++++++++++++++ 3 files changed, 128 insertions(+), 79 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index a934709aa..368aab382 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.CustomTridentUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; @@ -54,20 +55,16 @@ public class TestCommand extends BukkitCommandFeature { Player player = context.sender(); NamespacedKey namespacedKey = context.get("id"); ItemStack item = new ItemStack(Material.TRIDENT); - NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); - NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); - NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); - NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); // NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); // NamespacedKey customTridentX = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_x")); // NamespacedKey customTridentY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_y")); // NamespacedKey customTridentZ = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_z")); // NamespacedKey customTridentW = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_w")); item.editMeta(meta -> { - meta.getPersistentDataContainer().set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); - meta.getPersistentDataContainer().set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); - meta.getPersistentDataContainer().set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); - meta.getPersistentDataContainer().set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); + meta.getPersistentDataContainer().set(CustomTridentUtils.customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); + meta.getPersistentDataContainer().set(CustomTridentUtils.interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); + meta.getPersistentDataContainer().set(CustomTridentUtils.transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); + meta.getPersistentDataContainer().set(CustomTridentUtils.positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); // container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); // container.set(customTridentX, PersistentDataType.FLOAT, context.get("x")); // container.set(customTridentY, PersistentDataType.FLOAT, context.get("y")); 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 a8e27c484..fc184bf1a 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 @@ -10,10 +10,8 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; @@ -52,16 +50,11 @@ import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; -import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; import org.jetbrains.annotations.Nullable; -import org.joml.Quaternionf; -import org.joml.Vector3f; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; @@ -1615,45 +1608,7 @@ public class PacketConsumers { event.setCancelled(true); } } else if (entityType == Reflections.instance$EntityType$TRIDENT) { - int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); - Player player = (Player) user.platformPlayer(); - Trident trident = (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); - PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); - NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); - String customTrident = container.get(customTridentKey, PersistentDataType.STRING); - if (customTrident == null) return; - user.tridentView().put(entityId, List.of()); - NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); - NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); - NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); - Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); - Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); - Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); - float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$yRot.getByte(packet)); - float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$xRot.getByte(packet)); - player.sendMessage("加载自定义三叉戟实体1: " + packet); - Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); - Reflections.field$ClientboundAddEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); - Reflections.field$ClientboundAddEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); - List itemDisplayValues = new ArrayList<>(); - Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); - ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); - ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(0, 0, -2), itemDisplayValues); - ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(1, 1, 1, 1), itemDisplayValues); - if (VersionHelper.isOrAbove1_20_2()) { - ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); - ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues); - } else { - ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); - } - ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue((byte) 0, itemDisplayValues); - user.tridentView().put(entityId, itemDisplayValues); - player.sendMessage("加载自定义三叉戟实体2: " + entityId); - event.addDelayedTask(() -> { - user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); - player.sendMessage("加载自定义三叉戟实体3: " + itemDisplayValues); - }); + CustomTridentUtils.handleCustomTrident(user, event, packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); @@ -1665,16 +1620,7 @@ public class PacketConsumers { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); if (user.tridentView().containsKey(entityId)) { - Player player = (Player) user.platformPlayer(); - player.sendMessage("同步三叉戟实体位置: " + packet); - Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); - boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); - Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); - Object deltaMovement = Reflections.field$PositionMoveRotation$deltaMovement.get(positionMoveRotation); - float yRot = Reflections.field$PositionMoveRotation$yRot.getFloat(positionMoveRotation); - float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); - Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); - event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); + CustomTridentUtils.modifyCustomTridentPositionSync(event, packet, entityId); return; } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { @@ -1705,11 +1651,7 @@ public class PacketConsumers { int entityId = intList.getInt(i); user.entityView().remove(entityId); List entities = user.furnitureView().remove(entityId); - var removeTrident = user.tridentView().remove(entityId); - if (removeTrident != null && !removeTrident.isEmpty()) { - Player player = (Player) user.platformPlayer(); - player.sendMessage("移除三叉戟实体: " + removeTrident); - } + user.tridentView().remove(entityId); if (entities == null) continue; for (int subEntityId : entities) { isChange = true; @@ -2388,10 +2330,7 @@ public class PacketConsumers { try { int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); if (user.tridentView().containsKey(entityId)) { - Player player = (Player) user.platformPlayer(); - Object newPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId)); - player.sendMessage("设置三叉戟实体数据: " + newPacket); - event.replacePacket(newPacket); + CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); @@ -2402,12 +2341,7 @@ public class PacketConsumers { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); if (user.tridentView().containsKey(entityId)) { - float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); - float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); - Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); - Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); - Player player = (Player) user.platformPlayer(); - player.sendMessage("同步三叉戟实体位置: " + Math.clamp(-xRot, -90.0F, 90.0F) + ", " + -yRot); + CustomTridentUtils.modifyCustomTridentMove(packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java new file mode 100644 index 000000000..761b411e2 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -0,0 +1,118 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.entity.Trident; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import javax.annotation.Nullable; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class CustomTridentUtils { + public static final NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); + public static final NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); + public static final NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); + public static final NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); + + public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { + int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); + Trident trident = getTridentById(user, entityId); + if (!isCustomTrident(trident)) return; + user.tridentView().put(entityId, List.of()); + modifyCustomTridentPacket(packet); + List itemDisplayValues = buildEntityDataValues(trident); + user.tridentView().put(entityId, itemDisplayValues); + event.addDelayedTask(() -> { + user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); + }); + } + + @Nullable + public static Trident getTridentById(NetWorkUser user, int entityId) { + Player player = (Player) user.platformPlayer(); + return (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); + } + + public static boolean isCustomTrident(Trident trident) { + if (trident == null) return false; + PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); + String customTrident = container.get(customTridentKey, PersistentDataType.STRING); + return customTrident != null; + } + + public static void modifyCustomTridentPacket(Object packet) throws IllegalAccessException { + float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$yRot.getByte(packet)); + float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$xRot.getByte(packet)); + Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); + Reflections.field$ClientboundAddEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); + Reflections.field$ClientboundAddEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); + } + + public static List buildEntityDataValues(Trident trident) { + List itemDisplayValues = new ArrayList<>(); + PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); + String customTrident = container.get(customTridentKey, PersistentDataType.STRING); + Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); + Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); + Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); + Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); + ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(0, 0, -2), itemDisplayValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(1, 1, 1, 1), itemDisplayValues); + if (VersionHelper.isOrAbove1_20_2()) { + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues); + } else { + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); + } + ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue((byte) 0, itemDisplayValues); + return itemDisplayValues; + } + + // 这里需要补 ClientboundMoveEntityPacket 包 1.21.2+ + public static void modifyCustomTridentPositionSync(NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { + Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); + boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); + Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); + Object deltaMovement = Reflections.field$PositionMoveRotation$deltaMovement.get(positionMoveRotation); + float yRot = Reflections.field$PositionMoveRotation$yRot.getFloat(positionMoveRotation); + float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); + Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); + event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); + } + + public static void modifyCustomTridentMove(Object packet) throws IllegalAccessException { + float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); + float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); + Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); + Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); + } + + public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { + List newData = user.tridentView().get(entityId); + if (newData.isEmpty()) { + Trident trident = getTridentById(user, entityId); + if (!isCustomTrident(trident)) return; + newData = buildEntityDataValues(trident); + user.tridentView().put(entityId, newData); + } + event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, newData)); + } +} From 855d6ac15117289e10069e3fb4930a93beffb406 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 02:40:04 +0800 Subject: [PATCH 20/73] =?UTF-8?q?refactor(bukkit):=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E5=8F=8D=E5=B0=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/util/Reflections.java | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 36f6b5a5c..735382427 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6663,13 +6663,6 @@ public class Reflections { .map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 1)) .orElse(null); - public static final Class clazz$ClientboundTeleportEntityPacket = requireNonNull( - BukkitReflectionUtils.findReobfOrMojmapClass( - "network.protocol.game.PacketPlayOutEntityTeleport", - "network.protocol.game.ClientboundTeleportEntityPacket" - ) - ); - public static final Constructor constructor$ClientboundEntityPositionSyncPacket = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) .map(it -> ReflectionUtils.getTheOnlyConstructor(it)) .orElse(null); @@ -6697,34 +6690,4 @@ public class Reflections { clazz$ClientboundMoveEntityPacket, byte.class, 0 ) ); - // - // /** - // * 实体移动数据包 - // * - // *

1.20 ~ 1.21.1 版本传入参数:

- // *
    - // *
  • {@code FriendlyByteBuf} 需要按顺序写入: - // *
      - // *
    • {@code id} - VarInt 实体ID
    • - // *
    • {@code x} - Double X坐标
    • - // *
    • {@code y} - Double Y坐标
    • - // *
    • {@code z} - Double Z坐标
    • - // *
    • {@code yRot} - Byte 垂直旋转角度
    • - // *
    • {@code xRot} - Byte 水平旋转角度
    • - // *
    • {@code onGround} - Boolean 着地状态
    • - // *
    - // *
  • - // *
- // * - // *

1.21.2+ 版本传入参数:

- // *
    - // *
  • {@code id} - int 实体ID
  • - // *
  • {@code PositionMoveRotation change} - 位置和移动向量和旋转
  • - // *
  • {@code Set relatives} - 相对坐标标记集合
  • - // *
  • {@code onGround} - boolean 着地状态
  • - // *
- // */ - // public static final Constructor constructor$ClientboundTeleportEntityPacket = requireNonNull( - // ReflectionUtils.getConstructor(clazz$ClientboundTeleportEntityPacket, VersionHelper.isOrAbove1_21_2() ? 0 : 1) - // ); } From a7505ea90249b9b93c8075a63f93e828d1b332d3 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 04:33:37 +0800 Subject: [PATCH 21/73] =?UTF-8?q?refactor(bukkit):=20=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 20 ++++++++++++++++++- .../bukkit/util/CustomTridentUtils.java | 18 ++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 368aab382..c8468833e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.CustomTridentUtils; import net.momirealms.craftengine.core.item.Item; @@ -11,6 +12,7 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.checkerframework.checker.nullness.qual.NonNull; @@ -18,11 +20,14 @@ import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.BooleanParser; import org.incendo.cloud.parser.standard.IntegerParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; -import java.util.Objects; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -37,6 +42,7 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) + .required("forceUpdate", BooleanParser.booleanParser()) .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { @@ -53,6 +59,18 @@ public class TestCommand extends BukkitCommandFeature { // .required("w", FloatParser.floatParser()) .handler(context -> { Player player = context.sender(); + if (context.get("forceUpdate")) { + net.momirealms.craftengine.core.entity.player.Player cePlayer = plugin().adapt(player); + Collection tridents = player.getWorld().getEntitiesByClass(Trident.class); + List packets = new ArrayList<>(); + for (Trident trident : tridents) { + int entityId = FastNMS.INSTANCE.method$Entity$getId(FastNMS.INSTANCE.method$CraftEntity$getHandle(trident)); + player.sendMessage("COMMAND entityId: " + entityId); + packets.add(CustomTridentUtils.buildCustomTridentSetEntityDataPacket(cePlayer, entityId)); + } + cePlayer.sendPackets(packets, true); + return; + } NamespacedKey namespacedKey = context.get("id"); ItemStack item = new ItemStack(Material.TRIDENT); // NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index 761b411e2..aeb96c865 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -38,9 +38,7 @@ public class CustomTridentUtils { modifyCustomTridentPacket(packet); List itemDisplayValues = buildEntityDataValues(trident); user.tridentView().put(entityId, itemDisplayValues); - event.addDelayedTask(() -> { - user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); - }); + event.addDelayedTask(() -> user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true)); } @Nullable @@ -105,14 +103,20 @@ public class CustomTridentUtils { Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); } - public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { - List newData = user.tridentView().get(entityId); + public static Object buildCustomTridentSetEntityDataPacket(NetWorkUser user, int entityId) { + List newData = user.tridentView().getOrDefault(entityId, List.of()); if (newData.isEmpty()) { Trident trident = getTridentById(user, entityId); - if (!isCustomTrident(trident)) return; + if (!isCustomTrident(trident)) return null; newData = buildEntityDataValues(trident); user.tridentView().put(entityId, newData); } - event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, newData)); + return FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, newData); + } + + public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { + Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); + if (packet == null) return; + event.replacePacket(packet); } } From 0fa9b84a22b3af79ed948ef49664ecc5f338d659 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 07:04:41 +0800 Subject: [PATCH 22/73] =?UTF-8?q?refactor(bukkit):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=A4=A7=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复addEnchantment - 差一个移动路径补偿 - 求求你们不要喷我频繁提交了,除了这次最多还会有一个实现移动路径补偿的提交,如果你不想收到提交消息可以到我这个pr去取消通知 --- .../factory/ComponentItemFactory1_20_5.java | 4 +- .../item/factory/UniversalItemFactory.java | 8 +-- .../plugin/network/PacketConsumers.java | 8 ++- .../plugin/user/BukkitServerPlayer.java | 6 +++ .../bukkit/util/CustomTridentUtils.java | 51 ++++++++++++++----- .../craftengine/bukkit/util/Reflections.java | 30 ++++++++++- .../core/plugin/network/NetWorkUser.java | 2 + 7 files changed, 83 insertions(+), 26 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 08cc98ec3..f7b5e76ff 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -309,7 +309,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory map = EnchantmentUtils.toMap(enchant); - map.put(enchantment.toString(), enchantment.level()); + map.put(enchantment.id().toString(), enchantment.level()); item.setJavaComponent(ComponentTypes.ENCHANTMENTS, map); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to add enchantment", e); @@ -321,7 +321,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory map = EnchantmentUtils.toMap(enchant); - map.put(enchantment.toString(), enchantment.level()); + map.put(enchantment.id().toString(), enchantment.level()); item.setJavaComponent(ComponentTypes.STORED_ENCHANTMENTS, map); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to add stored enchantment", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index 787dba986..3dd72fe51 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -198,9 +198,9 @@ public class UniversalItemFactory extends BukkitItemFactory { return; } } - item.add(Map.of("id", enchantment.toString(), "lvl", (short) enchantment.level()), "Enchantments"); + item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "Enchantments"); } else { - item.set(List.of(Map.of("id", enchantment.toString(), "lvl", (short) enchantment.level())), "Enchantments"); + item.set(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "Enchantments"); } } @@ -214,9 +214,9 @@ public class UniversalItemFactory extends BukkitItemFactory { return; } } - item.add(Map.of("id", enchantment.toString(), "lvl", (short) enchantment.level()), "StoredEnchantments"); + item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "StoredEnchantments"); } else { - item.set(List.of(Map.of("id", enchantment.toString(), "lvl", (short) enchantment.level())), "StoredEnchantments"); + item.set(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "StoredEnchantments"); } } 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 1e36bba6a..1d4d4a8b6 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 @@ -1620,7 +1620,7 @@ public class PacketConsumers { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentPositionSync(event, packet, entityId); + CustomTridentUtils.modifyCustomTridentPositionSync(user, event, packet, entityId); return; } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { @@ -2329,9 +2329,7 @@ public class PacketConsumers { public static final TriConsumer SET_ENTITY_DATA = (user, event, packet) -> { try { int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); - if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); - } + CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); } @@ -2341,7 +2339,7 @@ public class PacketConsumers { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentMove(packet); + CustomTridentUtils.modifyCustomTridentMove(packet, user); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); 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 102c2cdaa..38122b1a0 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 @@ -94,6 +94,7 @@ public class BukkitServerPlayer extends Player { private final Map> furnitureView = new ConcurrentHashMap<>(); private final Map entityTypeView = new ConcurrentHashMap<>(); private final Map> tridentView = new ConcurrentHashMap<>(); + private final Map addTridentPacketView = new ConcurrentHashMap<>(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -743,6 +744,11 @@ public class BukkitServerPlayer extends Player { return this.tridentView; } + @Override + public Map addTridentPacketView() { + return this.addTridentPacketView; + } + public void setResendSound() { resentSoundTick = gameTicks(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index aeb96c865..2e35b45a4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -4,12 +4,14 @@ import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; @@ -33,25 +35,30 @@ public class CustomTridentUtils { public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); Trident trident = getTridentById(user, entityId); - if (!isCustomTrident(trident)) return; + if (notCustomTrident(trident)) return; user.tridentView().put(entityId, List.of()); modifyCustomTridentPacket(packet); + user.addTridentPacketView().put(entityId, packet); List itemDisplayValues = buildEntityDataValues(trident); user.tridentView().put(entityId, itemDisplayValues); - event.addDelayedTask(() -> user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true)); + user.sendPacket(packet, true); + user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); + event.setCancelled(true); } @Nullable public static Trident getTridentById(NetWorkUser user, int entityId) { Player player = (Player) user.platformPlayer(); - return (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); + Entity entity = FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); + if (entity instanceof Trident trident) return trident; + return null; } - public static boolean isCustomTrident(Trident trident) { - if (trident == null) return false; + public static boolean notCustomTrident(Trident trident) { + if (trident == null) return true; PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); String customTrident = container.get(customTridentKey, PersistentDataType.STRING); - return customTrident != null; + return customTrident == null; } public static void modifyCustomTridentPacket(Object packet) throws IllegalAccessException { @@ -64,9 +71,11 @@ public class CustomTridentUtils { public static List buildEntityDataValues(Trident trident) { List itemDisplayValues = new ArrayList<>(); - PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); + ItemStack itemStack = trident.getItemStack(); + PersistentDataContainer container = itemStack.getItemMeta().getPersistentDataContainer(); String customTrident = container.get(customTridentKey, PersistentDataType.STRING); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); + itemStack.getEnchantments().forEach((enchantment, level) -> item.addEnchantment(new Enchantment(Key.of(enchantment.getKey().toString()), level))); Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); @@ -85,7 +94,7 @@ public class CustomTridentUtils { } // 这里需要补 ClientboundMoveEntityPacket 包 1.21.2+ - public static void modifyCustomTridentPositionSync(NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { + public static void modifyCustomTridentPositionSync(NetWorkUser user, NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); @@ -94,11 +103,18 @@ public class CustomTridentUtils { float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); + // List path = SmoothMovementPathUtils.calculatePath(start, move, yRot, xRot); + // ((Player)user.platformPlayer()).sendMessage("entityId: " + entityId + " position: " + position + " deltaMovement: " + deltaMovement + " xRot: " + xRot + " yRot: " + yRot); } - public static void modifyCustomTridentMove(Object packet) throws IllegalAccessException { + public static void modifyCustomTridentMove(Object packet, NetWorkUser user) throws IllegalAccessException { + // int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); + // double xa = Reflections.field$ClientboundMoveEntityPacket$xa.getShort(packet); + // double ya = Reflections.field$ClientboundMoveEntityPacket$ya.getShort(packet); + // double za = Reflections.field$ClientboundMoveEntityPacket$za.getShort(packet); float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); + // ((Player)user.platformPlayer()).sendMessage("entityId: " + entityId + " xa: " + xa + " ya: " + ya + " za: " + za + " xRot: " + xRot + " yRot: " + yRot); Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); } @@ -107,7 +123,7 @@ public class CustomTridentUtils { List newData = user.tridentView().getOrDefault(entityId, List.of()); if (newData.isEmpty()) { Trident trident = getTridentById(user, entityId); - if (!isCustomTrident(trident)) return null; + if (notCustomTrident(trident)) return null; newData = buildEntityDataValues(trident); user.tridentView().put(entityId, newData); } @@ -115,8 +131,17 @@ public class CustomTridentUtils { } public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { - Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); - if (packet == null) return; - event.replacePacket(packet); + if (user.tridentView().containsKey(entityId)) { + Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); + if (packet == null) return; + event.replacePacket(packet); + } else { + Trident trident = getTridentById(user, entityId); + if (trident == null) return; + if (notCustomTrident(trident)) return; + Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); + if (packet == null) return; + event.replacePacket(packet); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 735382427..485df7122 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6103,6 +6103,10 @@ public class Reflections { ) ); + public static final Constructor constructor$ClientboundMoveEntityPacket$PosRot = requireNonNull( + ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundMoveEntityPacket$PosRot) + ); + public static final Class clazz$ClientboundRotateHeadPacket = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "network.protocol.game.PacketPlayOutEntityHeadRotation", @@ -6400,14 +6404,18 @@ public class Reflections { ); public static final int instance$EntityType$BLOCK_DISPLAY$registryId; + public static final int instance$EntityType$ITEM_DISPLAY$registryId; public static final int instance$EntityType$TEXT_DISPLAY$registryId; public static final int instance$EntityType$FALLING_BLOCK$registryId; + public static final int instance$EntityType$TRIDENT$registryId; static { try { instance$EntityType$BLOCK_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$BLOCK_DISPLAY); + instance$EntityType$ITEM_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ITEM_DISPLAY); instance$EntityType$TEXT_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TEXT_DISPLAY); instance$EntityType$FALLING_BLOCK$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FALLING_BLOCK); + instance$EntityType$TRIDENT$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TRIDENT); } catch (Exception e) { throw new RuntimeException(e); } @@ -6636,7 +6644,7 @@ public class Reflections { ); public static final Constructor constructor$PositionMoveRotation = Optional.ofNullable(clazz$PositionMoveRotation) - .map(it -> ReflectionUtils.getTheOnlyConstructor(it)) + .map(ReflectionUtils::getTheOnlyConstructor) .orElse(null); public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) @@ -6664,7 +6672,7 @@ public class Reflections { .orElse(null); public static final Constructor constructor$ClientboundEntityPositionSyncPacket = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) - .map(it -> ReflectionUtils.getTheOnlyConstructor(it)) + .map(ReflectionUtils::getTheOnlyConstructor) .orElse(null); public static final Field field$ClientboundAddEntityPacket$xRot = requireNonNull( @@ -6690,4 +6698,22 @@ public class Reflections { clazz$ClientboundMoveEntityPacket, byte.class, 0 ) ); + + public static final Field field$ClientboundMoveEntityPacket$xa = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundMoveEntityPacket, short.class, 0 + ) + ); + + public static final Field field$ClientboundMoveEntityPacket$ya = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundMoveEntityPacket, short.class, 1 + ) + ); + + public static final Field field$ClientboundMoveEntityPacket$za = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundMoveEntityPacket, short.class, 2 + ) + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index b1952a648..b74842ee1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -48,6 +48,8 @@ public interface NetWorkUser { Map> tridentView(); + Map addTridentPacketView(); + boolean clientModEnabled(); void setClientModState(boolean enable); From dec6cd4063603d7c58385015cfefc502fdd0eb03 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 09:56:42 +0800 Subject: [PATCH 23/73] =?UTF-8?q?refactor(bukkit):=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=89=E5=8F=89=E6=88=9F=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 接下来是设计配置文件 - 后面和优化一起推上去 --- .../plugin/network/PacketConsumers.java | 9 +++-- .../plugin/user/BukkitServerPlayer.java | 5 +-- .../bukkit/util/CustomTridentUtils.java | 35 +++++++++++++------ .../craftengine/bukkit/util/Reflections.java | 30 +++++++++++----- .../core/plugin/network/NetWorkUser.java | 3 +- 5 files changed, 58 insertions(+), 24 deletions(-) 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 1d4d4a8b6..5280c2131 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 @@ -35,6 +35,7 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetworkManager; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -1620,7 +1621,7 @@ public class PacketConsumers { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentPositionSync(user, event, packet, entityId); + CustomTridentUtils.modifyCustomTridentPositionSync(event, packet, entityId); return; } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { @@ -1651,6 +1652,10 @@ public class PacketConsumers { int entityId = intList.getInt(i); user.entityView().remove(entityId); List entities = user.furnitureView().remove(entityId); + SchedulerTask task = user.tridentTaskView().remove(entityId); + if (task != null) { + task.cancel(); + } user.tridentView().remove(entityId); if (entities == null) continue; for (int subEntityId : entities) { @@ -2339,7 +2344,7 @@ public class PacketConsumers { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentMove(packet, user); + CustomTridentUtils.modifyCustomTridentMove(packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); 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 38122b1a0..a9e2d0eba 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -94,7 +95,7 @@ public class BukkitServerPlayer extends Player { private final Map> furnitureView = new ConcurrentHashMap<>(); private final Map entityTypeView = new ConcurrentHashMap<>(); private final Map> tridentView = new ConcurrentHashMap<>(); - private final Map addTridentPacketView = new ConcurrentHashMap<>(); + private final Map addTridentPacketView = new ConcurrentHashMap<>(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -745,7 +746,7 @@ public class BukkitServerPlayer extends Player { } @Override - public Map addTridentPacketView() { + public Map tridentTaskView() { return this.addTridentPacketView; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index 2e35b45a4..d4a938669 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -6,7 +6,9 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.NMSPacketEvent; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -25,6 +27,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; public class CustomTridentUtils { public static final NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); @@ -35,15 +38,33 @@ public class CustomTridentUtils { public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); Trident trident = getTridentById(user, entityId); + Object serverEntity; + Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(trident); + Object tracker = Reflections.field$Entity$trackedEntity.get(nmsEntity); + if (tracker != null) { + serverEntity = Reflections.field$ChunkMap$TrackedEntity$serverEntity.get(tracker); + } else { + serverEntity = null; + } if (notCustomTrident(trident)) return; user.tridentView().put(entityId, List.of()); modifyCustomTridentPacket(packet); - user.addTridentPacketView().put(entityId, packet); List itemDisplayValues = buildEntityDataValues(trident); user.tridentView().put(entityId, itemDisplayValues); user.sendPacket(packet, true); user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); event.setCancelled(true); + if (serverEntity != null) { + // 这里直接暴力更新 + SchedulerTask task = CraftEngine.instance().scheduler().asyncRepeating(() -> { + try { + Reflections.method$ServerEntity$sendChanges.invoke(serverEntity); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to send entity data packet", e); + } + }, 5, 5, TimeUnit.MILLISECONDS); + user.tridentTaskView().put(entityId, task); + } } @Nullable @@ -93,8 +114,7 @@ public class CustomTridentUtils { return itemDisplayValues; } - // 这里需要补 ClientboundMoveEntityPacket 包 1.21.2+ - public static void modifyCustomTridentPositionSync(NetWorkUser user, NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { + public static void modifyCustomTridentPositionSync(NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); @@ -103,18 +123,11 @@ public class CustomTridentUtils { float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); - // List path = SmoothMovementPathUtils.calculatePath(start, move, yRot, xRot); - // ((Player)user.platformPlayer()).sendMessage("entityId: " + entityId + " position: " + position + " deltaMovement: " + deltaMovement + " xRot: " + xRot + " yRot: " + yRot); } - public static void modifyCustomTridentMove(Object packet, NetWorkUser user) throws IllegalAccessException { - // int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); - // double xa = Reflections.field$ClientboundMoveEntityPacket$xa.getShort(packet); - // double ya = Reflections.field$ClientboundMoveEntityPacket$ya.getShort(packet); - // double za = Reflections.field$ClientboundMoveEntityPacket$za.getShort(packet); + public static void modifyCustomTridentMove(Object packet) throws IllegalAccessException { float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); - // ((Player)user.platformPlayer()).sendMessage("entityId: " + entityId + " xa: " + xa + " ya: " + ya + " za: " + za + " xRot: " + xRot + " yRot: " + yRot); Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 485df7122..15fe735f3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6699,21 +6699,35 @@ public class Reflections { ) ); - public static final Field field$ClientboundMoveEntityPacket$xa = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundMoveEntityPacket, short.class, 0 + public static final Class clazz$ServerEntity = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "server.level.EntityTrackerEntry", + "server.level.ServerEntity" ) ); - public static final Field field$ClientboundMoveEntityPacket$ya = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundMoveEntityPacket, short.class, 1 + public static final Method method$ServerEntity$sendChanges = requireNonNull( + ReflectionUtils.getMethod( + clazz$ServerEntity, void.class, new String[]{ "sendChanges", "a" } ) ); - public static final Field field$ClientboundMoveEntityPacket$za = requireNonNull( + public static final Class clazz$ChunkMap$TrackedEntity = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "server.level.PlayerChunkMap$EntityTracker", + "server.level.ChunkMap$TrackedEntity" + ) + ); + + public static final Field field$Entity$trackedEntity = requireNonNull( ReflectionUtils.getDeclaredField( - clazz$ClientboundMoveEntityPacket, short.class, 2 + clazz$Entity, clazz$ChunkMap$TrackedEntity, 0 + ) + ); + + public static final Field field$ChunkMap$TrackedEntity$serverEntity = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ChunkMap$TrackedEntity, clazz$ServerEntity, 0 ) ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index b74842ee1..177e8d12c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.plugin.Plugin; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; @@ -48,7 +49,7 @@ public interface NetWorkUser { Map> tridentView(); - Map addTridentPacketView(); + Map tridentTaskView(); boolean clientModEnabled(); From 0c5d23a260d7acb2bfadf515161dfaafe565b1bf Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 11:29:28 +0800 Subject: [PATCH 24/73] =?UTF-8?q?refactor(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=B0=83=E8=AF=95=E7=9A=84=E4=B8=9C=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 准备设计配置格式 --- .../plugin/command/feature/TestCommand.java | 38 +++++---------- .../plugin/network/PacketConsumers.java | 4 +- .../bukkit/util/CustomTridentUtils.java | 48 ++++++++----------- 3 files changed, 37 insertions(+), 53 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index c8468833e..8cfc37e8a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -14,14 +14,14 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.BooleanParser; -import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.parser.standard.*; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; @@ -49,14 +49,10 @@ public class TestCommand extends BukkitCommandFeature { return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); } })) - .required("interpolationDelay", IntegerParser.integerParser()) - .required("transformationInterpolationDuration", IntegerParser.integerParser()) - .required("positionRotationInterpolationDuration", IntegerParser.integerParser()) - // .required("displayType", ByteParser.byteParser()) - // .required("x", FloatParser.floatParser()) - // .required("y", FloatParser.floatParser()) - // .required("z", FloatParser.floatParser()) - // .required("w", FloatParser.floatParser()) + .required("interpolationDuration", IntegerParser.integerParser()) + .required("displayType", ByteParser.byteParser((byte) 0, (byte) 8)) + .required("translation", StringParser.stringParser()) + .required("rotationLeft", StringParser.stringParser()) .handler(context -> { Player player = context.sender(); if (context.get("forceUpdate")) { @@ -73,21 +69,13 @@ public class TestCommand extends BukkitCommandFeature { } NamespacedKey namespacedKey = context.get("id"); ItemStack item = new ItemStack(Material.TRIDENT); - // NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); - // NamespacedKey customTridentX = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_x")); - // NamespacedKey customTridentY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_y")); - // NamespacedKey customTridentZ = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_z")); - // NamespacedKey customTridentW = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_w")); - item.editMeta(meta -> { - meta.getPersistentDataContainer().set(CustomTridentUtils.customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); - meta.getPersistentDataContainer().set(CustomTridentUtils.interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay")); - meta.getPersistentDataContainer().set(CustomTridentUtils.transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration")); - meta.getPersistentDataContainer().set(CustomTridentUtils.positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration")); - // container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); - // container.set(customTridentX, PersistentDataType.FLOAT, context.get("x")); - // container.set(customTridentY, PersistentDataType.FLOAT, context.get("y")); - // container.set(customTridentZ, PersistentDataType.FLOAT, context.get("z")); - // container.set(customTridentW, PersistentDataType.FLOAT, context.get("w")); + item.editMeta((meta) -> { + PersistentDataContainer container = meta.getPersistentDataContainer(); + container.set(CustomTridentUtils.customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); + container.set(CustomTridentUtils.interpolationDurationaKey, PersistentDataType.INTEGER, context.get("interpolationDuration")); + container.set(CustomTridentUtils.displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); + container.set(CustomTridentUtils.translationKey, PersistentDataType.STRING, context.get("translation")); + container.set(CustomTridentUtils.rotationLeftKey, PersistentDataType.STRING, context.get("rotationLeft")); Item ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null); Optional customModelData = ceItem.customModelData(); customModelData.ifPresent(meta::setCustomModelData); 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 5280c2131..4589fe4ab 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 @@ -2334,7 +2334,9 @@ public class PacketConsumers { public static final TriConsumer SET_ENTITY_DATA = (user, event, packet) -> { try { int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); - CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); + if (user.tridentView().containsKey(entityId)) { + CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); + } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index d4a938669..09a543a19 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -31,9 +31,10 @@ import java.util.concurrent.TimeUnit; public class CustomTridentUtils { public static final NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); - public static final NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay")); - public static final NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration")); - public static final NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration")); + public static final NamespacedKey interpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_duration")); + public static final NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); + public static final NamespacedKey translationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:translation")); + public static final NamespacedKey rotationLeftKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:rotation_left")); public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); @@ -47,7 +48,6 @@ public class CustomTridentUtils { serverEntity = null; } if (notCustomTrident(trident)) return; - user.tridentView().put(entityId, List.of()); modifyCustomTridentPacket(packet); List itemDisplayValues = buildEntityDataValues(trident); user.tridentView().put(entityId, itemDisplayValues); @@ -94,23 +94,26 @@ public class CustomTridentUtils { List itemDisplayValues = new ArrayList<>(); ItemStack itemStack = trident.getItemStack(); PersistentDataContainer container = itemStack.getItemMeta().getPersistentDataContainer(); - String customTrident = container.get(customTridentKey, PersistentDataType.STRING); + String customTrident = container.getOrDefault(customTridentKey, PersistentDataType.STRING, "craftengine:empty"); Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); itemStack.getEnchantments().forEach((enchantment, level) -> item.addEnchantment(new Enchantment(Key.of(enchantment.getKey().toString()), level))); - Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER); - Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER); - Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER); - ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues); - ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(0, 0, -2), itemDisplayValues); - ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(1, 1, 1, 1), itemDisplayValues); + Integer interpolationDurationa = container.getOrDefault(interpolationDurationaKey, PersistentDataType.INTEGER, 2); + Byte displayType = container.getOrDefault(displayTypeKey, PersistentDataType.BYTE, (byte) 0); + String translation = container.getOrDefault(translationKey, PersistentDataType.STRING, "0+0+0"); + String[] translations = translation.split("\\+"); + String rotationLeft = container.getOrDefault(rotationLeftKey, PersistentDataType.STRING, "0+0+0+0"); + String[] rotationLefts = rotationLeft.split("\\+"); + ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(-1, itemDisplayValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(Float.parseFloat(translations[0]), Float.parseFloat(translations[1]), Float.parseFloat(translations[2])), itemDisplayValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(Float.parseFloat(rotationLefts[0]), Float.parseFloat(rotationLefts[1]), Float.parseFloat(rotationLefts[2]), Float.parseFloat(rotationLefts[3])), itemDisplayValues); if (VersionHelper.isOrAbove1_20_2()) { - ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); - ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues); + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); } else { - ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues); + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); } ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue((byte) 0, itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(displayType, itemDisplayValues); return itemDisplayValues; } @@ -144,17 +147,8 @@ public class CustomTridentUtils { } public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { - if (user.tridentView().containsKey(entityId)) { - Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); - if (packet == null) return; - event.replacePacket(packet); - } else { - Trident trident = getTridentById(user, entityId); - if (trident == null) return; - if (notCustomTrident(trident)) return; - Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); - if (packet == null) return; - event.replacePacket(packet); - } + Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); + if (packet == null) return; + event.replacePacket(packet); } } From 29b0c9c8c5f6262daebc6fa873371c87b7434e97 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 13:51:03 +0800 Subject: [PATCH 25/73] =?UTF-8?q?refactor(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=B0=B4=E4=B8=8B=E6=B0=94=E6=B3=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 准备设计配置格式 --- .../plugin/command/feature/TestCommand.java | 13 ------- .../plugin/network/BukkitNetworkManager.java | 3 +- .../plugin/network/PacketConsumers.java | 23 ++++++------ .../bukkit/util/CustomTridentUtils.java | 37 ++++++++++++++----- .../bukkit/util/ParticleUtils.java | 1 + .../craftengine/bukkit/util/Reflections.java | 30 ++++++++++++++- 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 8cfc37e8a..c59ef90bd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -42,7 +42,6 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("forceUpdate", BooleanParser.booleanParser()) .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { @@ -55,18 +54,6 @@ public class TestCommand extends BukkitCommandFeature { .required("rotationLeft", StringParser.stringParser()) .handler(context -> { Player player = context.sender(); - if (context.get("forceUpdate")) { - net.momirealms.craftengine.core.entity.player.Player cePlayer = plugin().adapt(player); - Collection tridents = player.getWorld().getEntitiesByClass(Trident.class); - List packets = new ArrayList<>(); - for (Trident trident : tridents) { - int entityId = FastNMS.INSTANCE.method$Entity$getId(FastNMS.INSTANCE.method$CraftEntity$getHandle(trident)); - player.sendMessage("COMMAND entityId: " + entityId); - packets.add(CustomTridentUtils.buildCustomTridentSetEntityDataPacket(cePlayer, entityId)); - } - cePlayer.sendPackets(packets, true); - return; - } NamespacedKey namespacedKey = context.get("id"); ItemStack item = new ItemStack(Material.TRIDENT); item.editMeta((meta) -> { 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 599364ad9..95bca0475 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 @@ -152,7 +152,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket); registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); - registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY_ALL, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); @@ -172,7 +171,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA_BYTEBUFFER, this.packetIds.clientboundSetEntityDataPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); } public static BukkitNetworkManager instance() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 4589fe4ab..0ab795316 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 @@ -2008,10 +2008,20 @@ public class PacketConsumers { }; @SuppressWarnings("unchecked") - public static final BiConsumer SET_ENTITY_DATA_BYTEBUFFER = (user, event) -> { + public static final BiConsumer SET_ENTITY_DATA = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); + if (user.tridentView().containsKey(id)) { + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + List newPackedItems = CustomTridentUtils.buildCustomTridentSetEntityDataPacket(user, packedItems, id); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf); + return; + } Object entityType = user.entityView().get(id); if (entityType == Reflections.instance$EntityType$BLOCK_DISPLAY) { boolean isChanged = false; @@ -2331,17 +2341,6 @@ public class PacketConsumers { } }; - public static final TriConsumer SET_ENTITY_DATA = (user, event, packet) -> { - try { - int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet); - if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); - } - }; - public static final TriConsumer MOVE_ENTITY_ALL = (user, event, packet) -> { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index 09a543a19..5c4c270e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.NamespacedKey; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; @@ -39,6 +40,8 @@ public class CustomTridentUtils { public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); Trident trident = getTridentById(user, entityId); + if (trident == null) return; + World world = trident.getWorld(); Object serverEntity; Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(trident); Object tracker = Reflections.field$Entity$trackedEntity.get(nmsEntity); @@ -59,14 +62,26 @@ public class CustomTridentUtils { SchedulerTask task = CraftEngine.instance().scheduler().asyncRepeating(() -> { try { Reflections.method$ServerEntity$sendChanges.invoke(serverEntity); + if (!isInGround(nmsEntity)) { + world.spawnParticle(ParticleUtils.getParticle("BUBBLE"), trident.getLocation(), 1, 0, 0, 0, 0); + } } catch (IllegalAccessException | InvocationTargetException e) { CraftEngine.instance().logger().warn("Failed to send entity data packet", e); } - }, 5, 5, TimeUnit.MILLISECONDS); + }, 0, 5, TimeUnit.MILLISECONDS); user.tridentTaskView().put(entityId, task); } } + private static boolean isInGround(Object nmsEntity) throws IllegalAccessException, InvocationTargetException { + if (!Reflections.field$Entity$wasTouchingWater.getBoolean(nmsEntity)) return true; + if (VersionHelper.isOrAbove1_21_2()) { + return (boolean) Reflections.method$AbstractArrow$isInGround.invoke(nmsEntity); + } else { + return Reflections.field$AbstractArrow$inGround.getBoolean(nmsEntity); + } + } + @Nullable public static Trident getTridentById(NetWorkUser user, int entityId) { Player player = (Player) user.platformPlayer(); @@ -135,20 +150,22 @@ public class CustomTridentUtils { Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); } - public static Object buildCustomTridentSetEntityDataPacket(NetWorkUser user, int entityId) { + public static List buildCustomTridentSetEntityDataPacket(NetWorkUser user, List packedItems, int entityId) { + List newPackedItems = new ArrayList<>(); + for (Object packedItem : packedItems) { + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId < 8) { + newPackedItems.add(packedItem); + } + } List newData = user.tridentView().getOrDefault(entityId, List.of()); if (newData.isEmpty()) { Trident trident = getTridentById(user, entityId); - if (notCustomTrident(trident)) return null; + if (notCustomTrident(trident)) return newPackedItems; newData = buildEntityDataValues(trident); user.tridentView().put(entityId, newData); } - return FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, newData); - } - - public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) { - Object packet = buildCustomTridentSetEntityDataPacket(user, entityId); - if (packet == null) return; - event.replacePacket(packet); + newPackedItems.addAll(newData); + return newPackedItems; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index 6e847f6f9..e401be613 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -12,6 +12,7 @@ public class ParticleUtils { return switch (particle) { case "REDSTONE" -> Particle.valueOf("DUST"); case "VILLAGER_HAPPY", "HAPPY_VILLAGER" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY"); + case "BUBBLE" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "BUBBLE" : "WATER_BUBBLE"); default -> Particle.valueOf(particle); }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 15fe735f3..d71b22597 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6632,7 +6632,7 @@ public class Reflections { ) ); - public static final Field field$clazz$ClientboundSetEntityDataPacket$id = requireNonNull( + public static final Field field$ClientboundSetEntityDataPacket$id = requireNonNull( ReflectionUtils.getDeclaredField( clazz$ClientboundSetEntityDataPacket, int.class, 0 ) @@ -6730,4 +6730,32 @@ public class Reflections { clazz$ChunkMap$TrackedEntity, clazz$ServerEntity, 0 ) ); + + public static final Field field$Entity$wasTouchingWater = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$Entity, VersionHelper.isOrAbove1_21_2() + ? new String[]{ "wasTouchingWater", "ag" } : VersionHelper.isOrAbove1_20_5() + ? new String[]{ "wasTouchingWater", "aj" } : VersionHelper.isOrAbove1_20_2() + ? new String[]{ "wasTouchingWater", "ai" } : new String[]{ "wasTouchingWater", "ah" } + ) + ); + + public static final Class clazz$AbstractArrow = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.EntityArrow", + "world.entity.projectile.AbstractArrow" + ) + ); + + // 1.20~1.21.1 + public static final Field field$AbstractArrow$inGround = + ReflectionUtils.getDeclaredField( + clazz$AbstractArrow, boolean.class, 0 + ); + + // 1.21.2+ + public static final Method method$AbstractArrow$isInGround = + ReflectionUtils.getMethod( + clazz$AbstractArrow, boolean.class, VersionHelper.isOrAbove1_21_5() ? new String[]{ "isInGround", "e" } : new String[]{ "isInGround", "l" } + ); } From 79244af7447cd1f7e055860542d4a10f774bc8d7 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 10 May 2025 18:32:07 +0800 Subject: [PATCH 26/73] =?UTF-8?q?refactor(bukkit):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=B9=B6=E4=B8=94=E4=BC=98=E5=8C=96=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 7 - .../plugin/network/PacketConsumers.java | 4 +- .../bukkit/util/CustomTridentUtils.java | 140 +++++++++--------- .../craftengine/bukkit/util/Reflections.java | 126 ---------------- .../core/entity/CustomTrident.java | 8 + .../craftengine/core/item/ItemSettings.java | 22 +++ .../craftengine/core/util/MCUtils.java | 12 ++ gradle.properties | 2 +- 8 files changed, 111 insertions(+), 210 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index c59ef90bd..d9a512893 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -48,7 +48,6 @@ public class TestCommand extends BukkitCommandFeature { return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); } })) - .required("interpolationDuration", IntegerParser.integerParser()) .required("displayType", ByteParser.byteParser((byte) 0, (byte) 8)) .required("translation", StringParser.stringParser()) .required("rotationLeft", StringParser.stringParser()) @@ -57,12 +56,6 @@ public class TestCommand extends BukkitCommandFeature { NamespacedKey namespacedKey = context.get("id"); ItemStack item = new ItemStack(Material.TRIDENT); item.editMeta((meta) -> { - PersistentDataContainer container = meta.getPersistentDataContainer(); - container.set(CustomTridentUtils.customTridentKey, PersistentDataType.STRING, namespacedKey.asString()); - container.set(CustomTridentUtils.interpolationDurationaKey, PersistentDataType.INTEGER, context.get("interpolationDuration")); - container.set(CustomTridentUtils.displayTypeKey, PersistentDataType.BYTE, context.get("displayType")); - container.set(CustomTridentUtils.translationKey, PersistentDataType.STRING, context.get("translation")); - container.set(CustomTridentUtils.rotationLeftKey, PersistentDataType.STRING, context.get("rotationLeft")); Item ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null); Optional customModelData = ceItem.customModelData(); customModelData.ifPresent(meta::setCustomModelData); 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 0ab795316..183b20b31 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 @@ -1621,7 +1621,7 @@ public class PacketConsumers { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentPositionSync(event, packet, entityId); + event.replacePacket(CustomTridentUtils.buildCustomTridentPositionSync(packet, entityId)); return; } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { @@ -2345,7 +2345,7 @@ public class PacketConsumers { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); if (user.tridentView().containsKey(entityId)) { - CustomTridentUtils.modifyCustomTridentMove(packet); + event.replacePacket(CustomTridentUtils.buildCustomTridentMove(packet, entityId)); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java index 5c4c270e2..7f87849de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java @@ -4,6 +4,8 @@ import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.entity.CustomTrident; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -12,74 +14,51 @@ import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; -import org.joml.Quaternionf; -import org.joml.Vector3f; import javax.annotation.Nullable; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -import java.util.Objects; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.TimeUnit; public class CustomTridentUtils { - public static final NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident")); - public static final NamespacedKey interpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_duration")); - public static final NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type")); - public static final NamespacedKey translationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:translation")); - public static final NamespacedKey rotationLeftKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:rotation_left")); - public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException { + public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); Trident trident = getTridentById(user, entityId); if (trident == null) return; World world = trident.getWorld(); - Object serverEntity; Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(trident); - Object tracker = Reflections.field$Entity$trackedEntity.get(nmsEntity); - if (tracker != null) { - serverEntity = Reflections.field$ChunkMap$TrackedEntity$serverEntity.get(tracker); - } else { - serverEntity = null; - } + Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); + Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); if (notCustomTrident(trident)) return; - modifyCustomTridentPacket(packet); + Object newPacket = modifyCustomTridentPacket(packet, entityId); List itemDisplayValues = buildEntityDataValues(trident); user.tridentView().put(entityId, itemDisplayValues); - user.sendPacket(packet, true); + user.sendPacket(newPacket, true); user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); event.setCancelled(true); if (serverEntity != null) { // 这里直接暴力更新 SchedulerTask task = CraftEngine.instance().scheduler().asyncRepeating(() -> { - try { - Reflections.method$ServerEntity$sendChanges.invoke(serverEntity); - if (!isInGround(nmsEntity)) { - world.spawnParticle(ParticleUtils.getParticle("BUBBLE"), trident.getLocation(), 1, 0, 0, 0, 0); - } - } catch (IllegalAccessException | InvocationTargetException e) { - CraftEngine.instance().logger().warn("Failed to send entity data packet", e); + FastNMS.INSTANCE.method$ServerEntity$sendChanges(serverEntity); + if (canSpawnParticle(nmsEntity)) { + world.spawnParticle(ParticleUtils.getParticle("BUBBLE"), trident.getLocation(), 1, 0, 0, 0, 0); } }, 0, 5, TimeUnit.MILLISECONDS); user.tridentTaskView().put(entityId, task); } } - private static boolean isInGround(Object nmsEntity) throws IllegalAccessException, InvocationTargetException { - if (!Reflections.field$Entity$wasTouchingWater.getBoolean(nmsEntity)) return true; - if (VersionHelper.isOrAbove1_21_2()) { - return (boolean) Reflections.method$AbstractArrow$isInGround.invoke(nmsEntity); - } else { - return Reflections.field$AbstractArrow$inGround.getBoolean(nmsEntity); - } + private static boolean canSpawnParticle(Object nmsEntity) { + if (!FastNMS.INSTANCE.field$AbstractArrow$wasTouchingWater(nmsEntity)) return false; + return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); } @Nullable @@ -92,62 +71,75 @@ public class CustomTridentUtils { public static boolean notCustomTrident(Trident trident) { if (trident == null) return true; - PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer(); - String customTrident = container.get(customTridentKey, PersistentDataType.STRING); - return customTrident == null; + Optional> customItem = BukkitItemManager.instance().wrap(trident.getItemStack()).getCustomItem(); + return customItem.map(itemStackCustomItem -> itemStackCustomItem.settings().customTrident() == null).orElse(true); } - public static void modifyCustomTridentPacket(Object packet) throws IllegalAccessException { - float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$yRot.getByte(packet)); - float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$xRot.getByte(packet)); - Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY); - Reflections.field$ClientboundAddEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); - Reflections.field$ClientboundAddEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); + public static Object modifyCustomTridentPacket(Object packet, int entityId) { + UUID uuid = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$uuid(packet); + double x = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$x(packet); + double y = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$y(packet); + double z = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$z(packet); + float yRot = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$yRot(packet); + float xRot = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$xRot(packet); + Object type = Reflections.instance$EntityType$ITEM_DISPLAY; + int data = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$data(packet); + double xa = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$xa(packet); + double ya = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$ya(packet); + double za = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$za(packet); + double yHeadRot = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$yHeadRot(packet); + return FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( + entityId, uuid, x, y, z, + MCUtils.clamp(-xRot, -90.0F, 90.0F), -yRot, + type, data, FastNMS.INSTANCE.constructor$Vec3(xa, ya, za), yHeadRot + ); } public static List buildEntityDataValues(Trident trident) { List itemDisplayValues = new ArrayList<>(); ItemStack itemStack = trident.getItemStack(); - PersistentDataContainer container = itemStack.getItemMeta().getPersistentDataContainer(); - String customTrident = container.getOrDefault(customTridentKey, PersistentDataType.STRING, "craftengine:empty"); - Item item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null); + Optional> customItem = BukkitItemManager.instance().wrap(itemStack).getCustomItem(); + if (customItem.isEmpty()) return itemDisplayValues; + CustomTrident customTrident = customItem.get().settings().customTrident(); + Item item = BukkitItemManager.instance().createWrappedItem(customTrident.customTridentItemId(), null); itemStack.getEnchantments().forEach((enchantment, level) -> item.addEnchantment(new Enchantment(Key.of(enchantment.getKey().toString()), level))); - Integer interpolationDurationa = container.getOrDefault(interpolationDurationaKey, PersistentDataType.INTEGER, 2); - Byte displayType = container.getOrDefault(displayTypeKey, PersistentDataType.BYTE, (byte) 0); - String translation = container.getOrDefault(translationKey, PersistentDataType.STRING, "0+0+0"); - String[] translations = translation.split("\\+"); - String rotationLeft = container.getOrDefault(rotationLeftKey, PersistentDataType.STRING, "0+0+0+0"); - String[] rotationLefts = rotationLeft.split("\\+"); ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(-1, itemDisplayValues); - ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(Float.parseFloat(translations[0]), Float.parseFloat(translations[1]), Float.parseFloat(translations[2])), itemDisplayValues); - ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(Float.parseFloat(rotationLefts[0]), Float.parseFloat(rotationLefts[1]), Float.parseFloat(rotationLefts[2]), Float.parseFloat(rotationLefts[3])), itemDisplayValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(customTrident.translation(), itemDisplayValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(customTrident.rotationLefts(), itemDisplayValues); if (VersionHelper.isOrAbove1_20_2()) { - ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); - ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); } else { - ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(interpolationDurationa, itemDisplayValues); + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); } ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(displayType, itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(customTrident.displayType(), itemDisplayValues); return itemDisplayValues; } - public static void modifyCustomTridentPositionSync(NMSPacketEvent event, Object packet, int entityId) throws IllegalAccessException, InvocationTargetException, InstantiationException { - Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet); - boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet); - Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation); - Object deltaMovement = Reflections.field$PositionMoveRotation$deltaMovement.get(positionMoveRotation); - float yRot = Reflections.field$PositionMoveRotation$yRot.getFloat(positionMoveRotation); - float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation); - Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); - event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround)); + public static Object buildCustomTridentPositionSync(Object packet, int entityId) { + Object positionMoveRotation = FastNMS.INSTANCE.field$ClientboundEntityPositionSyncPacket$values(packet); + boolean onGround = FastNMS.INSTANCE.field$ClientboundEntityPositionSyncPacket$onGround(packet); + Object position = FastNMS.INSTANCE.field$PositionMoveRotation$position(positionMoveRotation); + Object deltaMovement = FastNMS.INSTANCE.field$PositionMoveRotation$deltaMovement(positionMoveRotation); + float yRot = FastNMS.INSTANCE.field$PositionMoveRotation$yRot(positionMoveRotation); + float xRot = FastNMS.INSTANCE.field$PositionMoveRotation$xRot(positionMoveRotation); + Object newPositionMoveRotation = FastNMS.INSTANCE.constructor$PositionMoveRotation(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F)); + return FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(entityId, newPositionMoveRotation, onGround); } - public static void modifyCustomTridentMove(Object packet) throws IllegalAccessException { - float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet)); - float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet)); - Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F))); - Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot)); + public static Object buildCustomTridentMove(Object packet, int entityId) { + short xa = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xa(packet); + short ya = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$ya(packet); + short za = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$za(packet); + float xRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xRot(packet)); + float yRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$yRot(packet)); + boolean onGround = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$onGround(packet); + return FastNMS.INSTANCE.constructor$ClientboundMoveEntityPacket$PosRot( + entityId, xa, ya, za, + MCUtils.packDegrees(-yRot), MCUtils.packDegrees(MCUtils.clamp(-xRot, -90.0F, 90.0F)), + onGround + ); } public static List buildCustomTridentSetEntityDataPacket(NetWorkUser user, List packedItems, int entityId) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index d71b22597..035a3e303 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6632,130 +6632,4 @@ public class Reflections { ) ); - public static final Field field$ClientboundSetEntityDataPacket$id = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundSetEntityDataPacket, int.class, 0 - ) - ); - - public static final Class clazz$PositionMoveRotation = - ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation") - ); - - public static final Constructor constructor$PositionMoveRotation = Optional.ofNullable(clazz$PositionMoveRotation) - .map(ReflectionUtils::getTheOnlyConstructor) - .orElse(null); - - public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0)) - .orElse(null); - - public static final Field field$ClientboundEntityPositionSyncPacket$onGround = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, boolean.class, 0)) - .orElse(null); - - public static final Field field$PositionMoveRotation$position = Optional.ofNullable(clazz$PositionMoveRotation) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 0)) - .orElse(null); - - public static final Field field$PositionMoveRotation$deltaMovement = Optional.ofNullable(clazz$PositionMoveRotation) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 1)) - .orElse(null); - - public static final Field field$PositionMoveRotation$yRot = Optional.ofNullable(clazz$PositionMoveRotation) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 0)) - .orElse(null); - - public static final Field field$PositionMoveRotation$xRot = Optional.ofNullable(clazz$PositionMoveRotation) - .map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 1)) - .orElse(null); - - public static final Constructor constructor$ClientboundEntityPositionSyncPacket = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket) - .map(ReflectionUtils::getTheOnlyConstructor) - .orElse(null); - - public static final Field field$ClientboundAddEntityPacket$xRot = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundAddEntityPacket, byte.class, 0 - ) - ); - - public static final Field field$ClientboundAddEntityPacket$yRot = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundAddEntityPacket, byte.class, 1 - ) - ); - - public static final Field field$ClientboundMoveEntityPacket$xRot = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundMoveEntityPacket, byte.class, 1 - ) - ); - - public static final Field field$ClientboundMoveEntityPacket$yRot = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ClientboundMoveEntityPacket, byte.class, 0 - ) - ); - - public static final Class clazz$ServerEntity = requireNonNull( - BukkitReflectionUtils.findReobfOrMojmapClass( - "server.level.EntityTrackerEntry", - "server.level.ServerEntity" - ) - ); - - public static final Method method$ServerEntity$sendChanges = requireNonNull( - ReflectionUtils.getMethod( - clazz$ServerEntity, void.class, new String[]{ "sendChanges", "a" } - ) - ); - - public static final Class clazz$ChunkMap$TrackedEntity = requireNonNull( - BukkitReflectionUtils.findReobfOrMojmapClass( - "server.level.PlayerChunkMap$EntityTracker", - "server.level.ChunkMap$TrackedEntity" - ) - ); - - public static final Field field$Entity$trackedEntity = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$Entity, clazz$ChunkMap$TrackedEntity, 0 - ) - ); - - public static final Field field$ChunkMap$TrackedEntity$serverEntity = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ChunkMap$TrackedEntity, clazz$ServerEntity, 0 - ) - ); - - public static final Field field$Entity$wasTouchingWater = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$Entity, VersionHelper.isOrAbove1_21_2() - ? new String[]{ "wasTouchingWater", "ag" } : VersionHelper.isOrAbove1_20_5() - ? new String[]{ "wasTouchingWater", "aj" } : VersionHelper.isOrAbove1_20_2() - ? new String[]{ "wasTouchingWater", "ai" } : new String[]{ "wasTouchingWater", "ah" } - ) - ); - - public static final Class clazz$AbstractArrow = requireNonNull( - BukkitReflectionUtils.findReobfOrMojmapClass( - "world.entity.projectile.EntityArrow", - "world.entity.projectile.AbstractArrow" - ) - ); - - // 1.20~1.21.1 - public static final Field field$AbstractArrow$inGround = - ReflectionUtils.getDeclaredField( - clazz$AbstractArrow, boolean.class, 0 - ); - - // 1.21.2+ - public static final Method method$AbstractArrow$isInGround = - ReflectionUtils.getMethod( - clazz$AbstractArrow, boolean.class, VersionHelper.isOrAbove1_21_5() ? new String[]{ "isInGround", "e" } : new String[]{ "isInGround", "l" } - ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java b/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java new file mode 100644 index 000000000..aed870c82 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.entity; + +import net.momirealms.craftengine.core.util.Key; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +public record CustomTrident(Key customTridentItemId, Byte displayType, Vector3f translation, Quaternionf rotationLefts) { +} 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 59d8a06a4..d9968d902 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 @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.item; +import net.momirealms.craftengine.core.entity.CustomTrident; import net.momirealms.craftengine.core.item.modifier.EquippableModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; @@ -9,6 +10,8 @@ import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.util.*; import java.util.stream.Collectors; @@ -22,6 +25,7 @@ public class ItemSettings { List anvilRepairItems = List.of(); boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; + CustomTrident customTrident; private ItemSettings() {} @@ -50,6 +54,7 @@ public class ItemSettings { newSettings.anvilRepairItems = settings.anvilRepairItems; newSettings.renameable = settings.renameable; newSettings.canPlaceRelatedVanillaBlock = settings.canPlaceRelatedVanillaBlock; + newSettings.customTrident = settings.customTrident; return newSettings; } @@ -65,6 +70,10 @@ public class ItemSettings { return settings; } + public CustomTrident customTrident() { + return customTrident; + } + public boolean canPlaceRelatedVanillaBlock() { return canPlaceRelatedVanillaBlock; } @@ -109,6 +118,11 @@ public class ItemSettings { return this; } + public ItemSettings customTrident(CustomTrident customTrident) { + this.customTrident = customTrident; + return this; + } + public ItemSettings canPlaceRelatedVanillaBlock(boolean canPlaceRelatedVanillaBlock) { this.canPlaceRelatedVanillaBlock = canPlaceRelatedVanillaBlock; return this; @@ -193,6 +207,14 @@ public class ItemSettings { boolean bool = (boolean) value; return settings -> settings.canPlaceRelatedVanillaBlock(bool); })); + registerFactory("custom-trident", (value -> { + Map args = MiscUtils.castToMap(value, false); + Key customTridentItemId = Key.of(args.get("custom-trident-item").toString()); + Byte displayType = Byte.valueOf(args.get("display-type").toString()); + Vector3f translation = MiscUtils.getAsVector3f(args.get("translation"), "translation"); + Quaternionf rotationLefts = MiscUtils.getAsQuaternionf(args.get("rotation-left"), "rotation-left"); + return settings -> settings.customTrident(new CustomTrident(customTridentItemId, displayType, translation, rotationLefts)); + })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 86f2093ca..ed472a652 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -197,4 +197,16 @@ public class MCUtils { public static float unpackDegrees(byte degrees) { return (float)(degrees * 360) / 256.0F; } + + public static int clamp(int value, int min, int max) { + return Math.min(Math.max(value, min), max); + } + + public static float clamp(float value, float min, float max) { + return value < min ? min : Math.min(value, max); + } + + public static double clamp(double value, double min, double max) { + return value < min ? min : Math.min(value, max); + } } diff --git a/gradle.properties b/gradle.properties index ccae7e353..9acb04c0c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.15 +nms_helper_version=0.65.17 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From d7f8f88106f9c885f012a4c4877013d5f6a109f5 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 10 May 2025 19:12:25 +0800 Subject: [PATCH 27/73] =?UTF-8?q?events=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 3 +- .../bukkit/block/BukkitBlockManager.java | 36 +++++++++++++++++++ .../bukkit/block/BukkitCustomBlock.java | 15 ++++---- .../craftengine/core/block/CustomBlock.java | 17 ++++++--- .../craftengine/core/block/EmptyBlock.java | 4 ++- .../core/block/InactiveCustomBlock.java | 4 ++- .../core/item/behavior/ItemBehaviors.java | 2 +- .../core/plugin/event/EventTrigger.java | 2 +- .../craftengine/core/util/MCUtils.java | 9 ++--- 9 files changed, 70 insertions(+), 22 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 3f0da67b9..4c2938cb0 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -297,4 +297,5 @@ warning.config.conflict_matcher.all_of.missing_terms: "Issue found in co warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." +warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 8bd60c4c7..af14fc4d1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -26,6 +26,10 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.BlockEventFunctions; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -421,6 +425,37 @@ public class BukkitBlockManager extends AbstractBlockManager { } } + Object eventsObj = ResourceConfigUtils.get(section, "events"); + EnumMap>> events = new EnumMap<>(EventTrigger.class); + if (eventsObj instanceof Map eventsSection) { + Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); + for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { + try { + EventTrigger eventTrigger = EventTrigger.valueOf(eventEntry.getKey().toUpperCase(Locale.ENGLISH)); + if (eventEntry.getValue() instanceof List list) { + if (list.size() == 1) { + events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); + } else if (list.size() == 2) { + events.put(eventTrigger, List.of( + BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), + BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) + )); + } else { + List> eventsList = new ArrayList<>(); + for (Object event : list) { + eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); + } + events.put(eventTrigger, eventsList); + } + } else if (eventEntry.getValue() instanceof Map eventSection) { + events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); + } + } + } + Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) .appearances(appearances) @@ -429,6 +464,7 @@ public class BukkitBlockManager extends AbstractBlockManager { .properties(properties) .settings(settings) .behavior(behaviors) + .events(events) .build(); // bind appearance and real state diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 209e34662..e0c550bdf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -9,6 +9,9 @@ import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -19,12 +22,11 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class BukkitCustomBlock extends CustomBlock { @@ -35,10 +37,11 @@ public class BukkitCustomBlock extends CustomBlock { Map appearances, Map variantMapper, BlockSettings settings, - Map behavior, + @NotNull EnumMap>> events, + @Nullable Map behavior, @Nullable LootTable lootTable ) { - super(id, holder, properties, appearances, variantMapper, settings, behavior, lootTable); + super(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); } @SuppressWarnings("unchecked") @@ -158,7 +161,7 @@ public class BukkitCustomBlock extends CustomBlock { // create or get block holder Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); - return new BukkitCustomBlock(id, holder, properties, appearances, variantMapper, settings, behavior, lootTable); + return new BukkitCustomBlock(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index ced0f7f7e..b30236ae6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -6,6 +6,9 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; @@ -15,10 +18,7 @@ import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.BiFunction; public abstract class CustomBlock { @@ -29,6 +29,7 @@ public abstract class CustomBlock { protected final BlockBehavior behavior; protected final List> placements; protected final ImmutableBlockState defaultState; + protected final EnumMap>> events; @Nullable protected final LootTable lootTable; @@ -39,6 +40,7 @@ public abstract class CustomBlock { @NotNull Map appearances, @NotNull Map variantMapper, @NotNull BlockSettings settings, + @NotNull EnumMap>> events, @Nullable Map behavior, @Nullable LootTable lootTable ) { @@ -48,6 +50,7 @@ public abstract class CustomBlock { this.lootTable = lootTable; this.properties = properties; this.placements = new ArrayList<>(); + this.events = events; this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); this.defaultState = this.variantProvider.getDefaultState(); this.behavior = BlockBehaviors.fromMap(this, behavior); @@ -168,11 +171,17 @@ public abstract class CustomBlock { protected BlockSettings settings; protected Map behavior; protected LootTable lootTable; + protected EnumMap>> events; protected Builder(Key id) { this.id = id; } + public Builder events(EnumMap>> events) { + this.events = events; + return this; + } + public Builder appearances(Map appearances) { this.appearances = appearances; return this; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index 4f827823b..4e5cca009 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; +import java.util.EnumMap; import java.util.Map; public class EmptyBlock extends CustomBlock { @@ -10,7 +12,7 @@ public class EmptyBlock extends CustomBlock { public static ImmutableBlockState STATE; public EmptyBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), new EnumMap<>(EventTrigger.class), null, null); INSTANCE = this; STATE = defaultState(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index db164c62e..a733f2bfd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -1,10 +1,12 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -12,7 +14,7 @@ public class InactiveCustomBlock extends CustomBlock { private final Map cachedData = new HashMap<>(); public InactiveCustomBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), new EnumMap<>(EventTrigger.class), null, null); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index af0524d2a..09d5eadc1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -28,7 +28,7 @@ public class ItemBehaviors { Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); ItemBehaviorFactory factory = BuiltInRegistries.ITEM_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.item.behavior.invalid_type", type.toString()); + throw new LocalizedResourceConfigException("warning.config.item.behavior.invalid_type", type); } return factory.create(pack, path, id, map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java index 2ea3421eb..5d26f6c1f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -4,5 +4,5 @@ public enum EventTrigger { USE_ITEM, USE_ITEM_ON, CONSUME, - + BREAK } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index ed472a652..869229f26 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -185,17 +185,12 @@ public class MCUtils { return next; } - public static int floor(float value) { - int i = (int) value; - return value < (float)i ? i - 1 : i; - } - public static byte packDegrees(float degrees) { - return (byte)floor(degrees * 256.0F / 360.0F); + return (byte) fastFloor(degrees * 256.0F / 360.0F); } public static float unpackDegrees(byte degrees) { - return (float)(degrees * 360) / 256.0F; + return (float) (degrees * 360) / 256.0F; } public static int clamp(int value, int min, int max) { From 519c861139e2b92573b74ba40c982ea8dee37d54 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 10 May 2025 20:16:01 +0800 Subject: [PATCH 28/73] =?UTF-8?q?=E9=87=8D=E6=9E=84entityview=E4=B8=BA?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureManager.java | 5 +- .../plugin/command/feature/TestCommand.java | 11 +- .../plugin/network/BukkitNetworkManager.java | 9 +- .../plugin/network/PacketConsumers.java | 176 +++--------------- .../handler/ArmorStandPacketHandler.java | 62 ++++++ .../handler/BlockDisplayPacketHandler.java | 76 ++++++++ .../handler/CustomTridentPacketHandler.java} | 29 +-- .../handler/FurniturePacketHandler.java | 20 ++ .../handler/TextDisplayPacketHandler.java | 59 ++++++ .../plugin/user/BukkitServerPlayer.java | 34 +--- .../craftengine/bukkit/util/Reflections.java | 2 + .../plugin/network/ByteBufPacketEvent.java | 30 +-- .../plugin/network/EntityPacketHandler.java | 13 ++ .../core}/plugin/network/NMSPacketEvent.java | 2 +- .../core/plugin/network/NetWorkUser.java | 10 +- 15 files changed, 283 insertions(+), 255 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/{util/CustomTridentUtils.java => plugin/network/handler/CustomTridentPacketHandler.java} (86%) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java rename {bukkit/src/main/java/net/momirealms/craftengine/bukkit => core/src/main/java/net/momirealms/craftengine/core}/plugin/network/ByteBufPacketEvent.java (53%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java rename {bukkit/src/main/java/net/momirealms/craftengine/bukkit => core/src/main/java/net/momirealms/craftengine/core}/plugin/network/NMSPacketEvent.java (95%) 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 4b79032ed..e2d204063 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 @@ -4,6 +4,7 @@ import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitB import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; @@ -301,14 +302,14 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture)); furniture.initializeColliders(); for (Player player : display.getTrackedPlayers()) { - this.plugin.adapt(player).furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); + this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player)); } } } else { LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture)); for (Player player : display.getTrackedPlayers()) { - this.plugin.adapt(player).furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); + this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player)); } if (preventChange) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index d9a512893..2dc46a53d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,9 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.util.CustomTridentUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; @@ -12,22 +10,17 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.*; +import org.incendo.cloud.parser.standard.ByteParser; +import org.incendo.cloud.parser.standard.StringParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; 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 95bca0475..cf568a561 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 @@ -14,9 +14,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.network.ConnectionState; -import net.momirealms.craftengine.core.plugin.network.NetWorkUser; -import net.momirealms.craftengine.core.plugin.network.NetworkManager; +import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -152,7 +150,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket); registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); - registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY_ALL, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(PacketConsumers.MOVE_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); @@ -549,7 +547,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes FriendlyByteBuf buf = new FriendlyByteBuf(buffer); int preProcessIndex = buf.readerIndex(); int packetId = buf.readVarInt(); - ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf); + int preIndex = buf.readerIndex(); + ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); BukkitNetworkManager.this.handleByteBufPacket(this.player, event); if (event.isCancelled()) { buf.clear(); 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 183b20b31..7aae1ac37 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 @@ -17,6 +17,10 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; +import net.momirealms.craftengine.bukkit.plugin.network.handler.ArmorStandPacketHandler; +import net.momirealms.craftengine.bukkit.plugin.network.handler.BlockDisplayPacketHandler; +import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; +import net.momirealms.craftengine.bukkit.plugin.network.handler.TextDisplayPacketHandler; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -31,11 +35,7 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.network.ConnectionState; -import net.momirealms.craftengine.core.plugin.network.NetWorkUser; -import net.momirealms.craftengine.core.plugin.network.NetworkManager; -import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; -import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -421,7 +421,8 @@ public class PacketConsumers { return; } EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); - outer: { + outer: + { for (Object entry : enums) { if (entry == Reflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { break outer; @@ -1578,9 +1579,11 @@ public class PacketConsumers { buf.writeShort(za); } } else if (type == Reflections.instance$EntityType$BLOCK_DISPLAY$registryId) { - user.entityView().put(id, Reflections.instance$EntityType$BLOCK_DISPLAY); + user.entityPacketHandlers().put(id, BlockDisplayPacketHandler.INSTANCE); } else if (type == Reflections.instance$EntityType$TEXT_DISPLAY$registryId) { - user.entityView().put(id, Reflections.instance$EntityType$TEXT_DISPLAY); + user.entityPacketHandlers().put(id, TextDisplayPacketHandler.INSTANCE); + } else if (type == Reflections.instance$EntityType$ARMOR_STAND$registryId) { + user.entityPacketHandlers().put(id, ArmorStandPacketHandler.INSTANCE); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); @@ -1595,7 +1598,7 @@ public class PacketConsumers { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { - user.furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); + user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(furniture.fakeEntityIds())); user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); @@ -1608,8 +1611,6 @@ public class PacketConsumers { if (furniture != null) { event.setCancelled(true); } - } else if (entityType == Reflections.instance$EntityType$TRIDENT) { - CustomTridentUtils.handleCustomTrident(user, event, packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); @@ -1620,10 +1621,6 @@ public class PacketConsumers { public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); - if (user.tridentView().containsKey(entityId)) { - event.replacePacket(CustomTridentUtils.buildCustomTridentPositionSync(packet, entityId)); - return; - } if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); } @@ -1650,17 +1647,9 @@ public class PacketConsumers { IntList intList = buf.readIntIdList(); for (int i = 0, size = intList.size(); i < size; i++) { int entityId = intList.getInt(i); - user.entityView().remove(entityId); - List entities = user.furnitureView().remove(entityId); - SchedulerTask task = user.tridentTaskView().remove(entityId); - if (task != null) { - task.cancel(); - } - user.tridentView().remove(entityId); - if (entities == null) continue; - for (int subEntityId : entities) { + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { isChange = true; - intList.add(subEntityId); } } if (isChange) { @@ -2012,131 +2001,11 @@ public class PacketConsumers { try { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); - if (user.tridentView().containsKey(id)) { - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - List newPackedItems = CustomTridentUtils.buildCustomTridentSetEntityDataPacket(user, packedItems, id); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf); - return; + EntityPacketHandler handler = user.entityPacketHandlers().get(id); + if (handler != null) { + handler.handleSetEntityData(user, event); } - Object entityType = user.entityView().get(id); - if (entityType == Reflections.instance$EntityType$BLOCK_DISPLAY) { - boolean isChanged = false; - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - for (int i = 0; i < packedItems.size(); i++) { - Object packedItem = packedItems.get(i); - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.BLOCK_STATE_DATA_ID) { - Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = remap(stateId); - } else { - newStateId = remapMOD(stateId); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) - )); - isChanged = true; - } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { - Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isPresent()) { - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) - )); - isChanged = true; - } - } - } - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); - } - } else if (entityType == Reflections.instance$EntityType$TEXT_DISPLAY) { - if (Config.interceptTextDisplay()) { - boolean isChanged = false; - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - for (int i = 0; i < packedItems.size(); i++) { - Object packedItem = packedItems.get(i); - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.TEXT_DATA_ID) { - Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (textComponent == Reflections.instance$Component$empty) break; - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component))); - isChanged = true; - break; - } - } - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); - } - } - } else if (entityType == Reflections.instance$EntityType$ARMOR_STAND) { - if (Config.interceptArmorStand()) { - boolean isChanged = false; - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - for (int i = 0; i < packedItems.size(); i++) { - Object packedItem = packedItems.get(i); - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { - Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isPresent()) { - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); - isChanged = true; - break; - } - } - } - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); - } - } - } else if (Config.interceptEntityName()) { + if (Config.interceptEntityName()) { boolean isChanged = false; List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); for (int i = 0; i < packedItems.size(); i++) { @@ -2187,7 +2056,8 @@ public class PacketConsumers { if (hasDisplay) { displayName = buf.readNbt(false); } - outside : if (displayName != null) { + outside: + if (displayName != null) { Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); if (tokens.isEmpty()) break outside; Component component = AdventureHelper.tagToComponent(displayName); @@ -2341,12 +2211,10 @@ public class PacketConsumers { } }; - public static final TriConsumer MOVE_ENTITY_ALL = (user, event, packet) -> { + public static final TriConsumer MOVE_AND_ROTATE_ENTITY = (user, event, packet) -> { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); - if (user.tridentView().containsKey(entityId)) { - event.replacePacket(CustomTridentUtils.buildCustomTridentMove(packet, entityId)); - } + } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java new file mode 100644 index 000000000..769363ce5 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java @@ -0,0 +1,62 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ArmorStandPacketHandler implements EntityPacketHandler { + public static final ArmorStandPacketHandler INSTANCE = new ArmorStandPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptArmorStand()) { + return; + } + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isPresent()) { + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); + isChanged = true; + break; + } + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java new file mode 100644 index 000000000..8ed3f8f7b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java @@ -0,0 +1,76 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class BlockDisplayPacketHandler implements EntityPacketHandler { + public static final BlockDisplayPacketHandler INSTANCE = new BlockDisplayPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.BLOCK_STATE_DATA_ID) { + Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + int stateId = BlockStateUtils.blockStateToId(blockState); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = PacketConsumers.remap(stateId); + } else { + newStateId = PacketConsumers.remapMOD(stateId); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) + )); + isChanged = true; + } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isPresent()) { + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) + )); + isChanged = true; + } + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java similarity index 86% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java index 7f87849de..487fa4152 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/CustomTridentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java @@ -1,16 +1,15 @@ -package net.momirealms.craftengine.bukkit.util; +package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.CustomTrident; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; -import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -25,9 +24,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.TimeUnit; -public class CustomTridentUtils { +public final class CustomTridentPacketHandler { + + private CustomTridentPacketHandler() {} public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); @@ -40,19 +40,10 @@ public class CustomTridentUtils { if (notCustomTrident(trident)) return; Object newPacket = modifyCustomTridentPacket(packet, entityId); List itemDisplayValues = buildEntityDataValues(trident); - user.tridentView().put(entityId, itemDisplayValues); user.sendPacket(newPacket, true); user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); event.setCancelled(true); if (serverEntity != null) { - // 这里直接暴力更新 - SchedulerTask task = CraftEngine.instance().scheduler().asyncRepeating(() -> { - FastNMS.INSTANCE.method$ServerEntity$sendChanges(serverEntity); - if (canSpawnParticle(nmsEntity)) { - world.spawnParticle(ParticleUtils.getParticle("BUBBLE"), trident.getLocation(), 1, 0, 0, 0, 0); - } - }, 0, 5, TimeUnit.MILLISECONDS); - user.tridentTaskView().put(entityId, task); } } @@ -150,14 +141,6 @@ public class CustomTridentUtils { newPackedItems.add(packedItem); } } - List newData = user.tridentView().getOrDefault(entityId, List.of()); - if (newData.isEmpty()) { - Trident trident = getTridentById(user, entityId); - if (notCustomTrident(trident)) return newPackedItems; - newData = buildEntityDataValues(trident); - user.tridentView().put(entityId, newData); - } - newPackedItems.addAll(newData); return newPackedItems; } } 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 new file mode 100644 index 000000000..70c0d6778 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import it.unimi.dsi.fastutil.ints.IntList; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; + +import java.util.List; + +public class FurniturePacketHandler implements EntityPacketHandler { + private final List fakeEntities; + + public FurniturePacketHandler(List fakeEntities) { + this.fakeEntities = fakeEntities; + } + + @Override + public boolean handleEntitiesRemove(IntList entityIds) { + entityIds.addAll(this.fakeEntities); + return true; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java new file mode 100644 index 000000000..35eb26ddd --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java @@ -0,0 +1,59 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.List; +import java.util.Map; + +public class TextDisplayPacketHandler implements EntityPacketHandler { + public static final TextDisplayPacketHandler INSTANCE = new TextDisplayPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTextDisplay()) { + return; + } + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.TEXT_DATA_ID) { + Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (textComponent == Reflections.instance$Component$empty) break; + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component))); + isChanged = true; + break; + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} 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 a9e2d0eba..b1f33c52d 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 @@ -19,8 +19,8 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; 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.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -91,11 +91,8 @@ public class BukkitServerPlayer extends Player { // cache interaction range here private int lastUpdateInteractionRangeTick; private double cachedInteractionRange; - // for better fake furniture visual sync - private final Map> furnitureView = new ConcurrentHashMap<>(); - private final Map entityTypeView = new ConcurrentHashMap<>(); - private final Map> tridentView = new ConcurrentHashMap<>(); - private final Map addTridentPacketView = new ConcurrentHashMap<>(); + + private final Map entityTypeView = new ConcurrentHashMap<>(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -107,13 +104,6 @@ public class BukkitServerPlayer extends Player { this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); this.uuid = player.getUniqueId(); this.name = player.getName(); -// if (Reflections.method$CraftPlayer$setSimplifyContainerDesyncCheck != null) { -// try { -// Reflections.method$CraftPlayer$setSimplifyContainerDesyncCheck.invoke(player, true); -// } catch (Exception e) { -// this.plugin.logger().warn("Failed to setSimplifyContainerDesyncCheck", e); -// } -// } } @Override @@ -731,25 +721,10 @@ public class BukkitServerPlayer extends Player { } @Override - public Map> furnitureView() { - return this.furnitureView; - } - - @Override - public Map entityView() { + public Map entityPacketHandlers() { return this.entityTypeView; } - @Override - public Map> tridentView() { - return this.tridentView; - } - - @Override - public Map tridentTaskView() { - return this.addTridentPacketView; - } - public void setResendSound() { resentSoundTick = gameTicks(); } @@ -812,7 +787,6 @@ public class BukkitServerPlayer extends Player { @Override public void clearView() { this.entityTypeView.clear(); - this.furnitureView.clear(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 035a3e303..1ab0294db 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6408,6 +6408,7 @@ public class Reflections { public static final int instance$EntityType$TEXT_DISPLAY$registryId; public static final int instance$EntityType$FALLING_BLOCK$registryId; public static final int instance$EntityType$TRIDENT$registryId; + public static final int instance$EntityType$ARMOR_STAND$registryId; static { try { @@ -6416,6 +6417,7 @@ public class Reflections { instance$EntityType$TEXT_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TEXT_DISPLAY); instance$EntityType$FALLING_BLOCK$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FALLING_BLOCK); instance$EntityType$TRIDENT$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TRIDENT); + instance$EntityType$ARMOR_STAND$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ARMOR_STAND); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/ByteBufPacketEvent.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ByteBufPacketEvent.java similarity index 53% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/ByteBufPacketEvent.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/network/ByteBufPacketEvent.java index 023bb5b94..585921ca0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/ByteBufPacketEvent.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ByteBufPacketEvent.java @@ -1,31 +1,28 @@ -package net.momirealms.craftengine.bukkit.plugin.network; +package net.momirealms.craftengine.core.plugin.network; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.FriendlyByteBuf; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - public class ByteBufPacketEvent implements Cancellable { private boolean cancelled; - private List delayedTasks = null; private final FriendlyByteBuf buf; private boolean changed; private final int packetID; + private final int preIndex; - public ByteBufPacketEvent(int packetID, FriendlyByteBuf buf) { + public ByteBufPacketEvent(int packetID, FriendlyByteBuf buf, int preIndex) { this.buf = buf; this.packetID = packetID; + this.preIndex = preIndex; } public int packetID() { - return packetID; + return this.packetID; } public FriendlyByteBuf getBuffer() { - return buf; + this.buf.readerIndex(this.preIndex); + return this.buf; } public void setChanged(boolean dirty) { @@ -33,18 +30,7 @@ public class ByteBufPacketEvent implements Cancellable { } public boolean changed() { - return changed; - } - - public void addDelayedTask(Runnable task) { - if (delayedTasks == null) { - delayedTasks = new ArrayList<>(); - } - delayedTasks.add(task); - } - - public List getDelayedTasks() { - return Optional.ofNullable(delayedTasks).orElse(Collections.emptyList()); + return this.changed; } @Override 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 new file mode 100644 index 000000000..8a2c9e78e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.plugin.network; + +import it.unimi.dsi.fastutil.ints.IntList; + +public interface EntityPacketHandler { + + default boolean handleEntitiesRemove(IntList entityIds) { + return false; + } + + default void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NMSPacketEvent.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NMSPacketEvent.java similarity index 95% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NMSPacketEvent.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/network/NMSPacketEvent.java index d753f4815..e95726ddb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NMSPacketEvent.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NMSPacketEvent.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.plugin.network; +package net.momirealms.craftengine.core.plugin.network; import net.momirealms.craftengine.core.util.Cancellable; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 177e8d12c..cf9442fee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -2,11 +2,9 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.plugin.Plugin; -import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; -import java.util.List; import java.util.Map; import java.util.UUID; @@ -43,13 +41,7 @@ public interface NetWorkUser { Object platformPlayer(); - Map> furnitureView(); - - Map entityView(); - - Map> tridentView(); - - Map tridentTaskView(); + Map entityPacketHandlers(); boolean clientModEnabled(); From 3483275cdfd7ca274cc1c66c9b37032d780dd5d8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 10 May 2025 22:04:19 +0800 Subject: [PATCH 29/73] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=BC=B9=E5=B0=84?= =?UTF-8?q?=E7=89=A9=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bettermodel/BetterModelModel.java | 4 +- .../modelengine/ModelEngineModel.java | 4 +- .../block/behavior/CropBlockBehavior.java | 2 +- .../block/behavior/GrassBlockBehavior.java | 2 +- .../block/behavior/SaplingBlockBehavior.java | 2 +- .../bukkit/entity/BukkitEntity.java | 4 +- .../furniture/BukkitFurnitureElement.java | 4 +- .../furniture/BukkitFurnitureManager.java | 2 + .../projectile/BukkitCustomProjectile.java | 14 ++ .../entity/projectile/BukkitProjectile.java | 11 ++ .../projectile/BukkitProjectileManager.java | 81 +++++++++ .../bukkit/item/ItemEventListener.java | 4 + .../bukkit/plugin/BukkitCraftEngine.java | 2 + .../plugin/command/feature/TestCommand.java | 2 +- .../plugin/network/PacketConsumers.java | 25 ++- .../FurnitureCollisionPacketHandler.java | 14 ++ .../handler/FurniturePacketHandler.java | 7 + ...dler.java => ProjectilePacketHandler.java} | 159 +++++++++--------- .../bukkit/util/ParticleUtils.java | 8 +- .../core/entity/AbstractEntity.java | 11 ++ .../entity/{furniture => }/Billboard.java | 2 +- .../core/entity/CustomTrident.java | 8 - .../craftengine/core/entity/Entity.java | 29 ++-- .../{furniture => }/ItemDisplayContext.java | 2 +- .../furniture/AbstractFurnitureElement.java | 2 + .../core/entity/furniture/ExternalModel.java | 4 +- .../entity/furniture/FurnitureElement.java | 2 + .../entity/furniture/FurnitureManager.java | 4 +- .../core/entity/player/Player.java | 4 +- .../projectile/AbstractCustomProjectile.java | 30 ++++ .../entity/projectile/CustomProjectile.java | 12 ++ .../core/entity/projectile/Projectile.java | 6 + .../entity/projectile/ProjectileManager.java | 10 ++ .../entity/projectile/ProjectileMeta.java | 9 + .../craftengine/core/item/ItemSettings.java | 23 +-- .../craftengine/core/plugin/CraftEngine.java | 10 ++ .../craftengine/core/plugin/Plugin.java | 3 + .../parameter/PlayerParameterProvider.java | 10 +- .../plugin/network/EntityPacketHandler.java | 6 + .../craftengine/core/util/Direction.java | 4 +- .../craftengine/core/world/HitResult.java | 4 +- 41 files changed, 389 insertions(+), 157 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectile.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/{CustomTridentPacketHandler.java => ProjectilePacketHandler.java} (60%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java rename core/src/main/java/net/momirealms/craftengine/core/entity/{furniture => }/Billboard.java (80%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java rename core/src/main/java/net/momirealms/craftengine/core/entity/{furniture => }/ItemDisplayContext.java (86%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/AbstractCustomProjectile.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/CustomProjectile.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/Projectile.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bettermodel/BetterModelModel.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bettermodel/BetterModelModel.java index aeec3c863..5dfa9c816 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bettermodel/BetterModelModel.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bettermodel/BetterModelModel.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.bukkit.compatibility.bettermodel; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel; public class BetterModelModel extends AbstractExternalModel { @@ -15,7 +15,7 @@ public class BetterModelModel extends AbstractExternalModel { } @Override - public void bindModel(Entity entity) { + public void bindModel(AbstractEntity entity) { org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.literalObject(); BetterModelUtils.bindModel(bukkitEntity, id()); } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/modelengine/ModelEngineModel.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/modelengine/ModelEngineModel.java index cba3b00ce..8ce03f0d6 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/modelengine/ModelEngineModel.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/modelengine/ModelEngineModel.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.bukkit.compatibility.modelengine; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel; public class ModelEngineModel extends AbstractExternalModel { @@ -15,7 +15,7 @@ public class ModelEngineModel extends AbstractExternalModel { } @Override - public void bindModel(Entity entity) { + public void bindModel(AbstractEntity entity) { org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.literalObject(); ModelEngineUtils.bindModel(bukkitEntity, id()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index e5681c5fb..e4e6be99d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -159,7 +159,7 @@ public class CropBlockBehavior extends BushBlockBehavior { } FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); if (sendParticles) { - world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25); + world.spawnParticle(ParticleUtils.HAPPY_VILLAGER, x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java index 3b0c868bc..14b4efb72 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java @@ -52,7 +52,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); - world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 1.5, z + 0.5, 20, 2, 0, 2); + world.spawnParticle(ParticleUtils.HAPPY_VILLAGER, x + 0.5, y + 1.5, z + 0.5, 20, 2, 0, 2); } return true; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 06d41970e..6242f1103 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -120,7 +120,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); - world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25); + world.spawnParticle(ParticleUtils.HAPPY_VILLAGER, x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25); } return success; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index d8bc859de..ce7748ec8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -2,14 +2,14 @@ package net.momirealms.craftengine.bukkit.entity; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import java.lang.ref.WeakReference; -public class BukkitEntity extends Entity { +public class BukkitEntity extends AbstractEntity { private final WeakReference entity; public BukkitEntity(org.bukkit.entity.Entity entity) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index f1b88b0fb..ec41936ac 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -5,8 +5,8 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement; -import net.momirealms.craftengine.core.entity.furniture.Billboard; -import net.momirealms.craftengine.core.entity.furniture.ItemDisplayContext; +import net.momirealms.craftengine.core.entity.Billboard; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; 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 e2d204063..ca76fb096 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 @@ -7,6 +7,8 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.entity.Billboard; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java new file mode 100644 index 000000000..45c4193bd --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.bukkit.entity.projectile; + +import net.momirealms.craftengine.core.entity.projectile.AbstractCustomProjectile; +import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; +import net.momirealms.craftengine.core.item.Item; +import org.bukkit.entity.Projectile; +import org.bukkit.inventory.ItemStack; + +public class BukkitCustomProjectile extends AbstractCustomProjectile { + + public BukkitCustomProjectile(ProjectileMeta meta, Projectile projectile, Item projectileItem) { + super(meta, new BukkitProjectile(projectile), projectileItem); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectile.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectile.java new file mode 100644 index 000000000..5ddf01516 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectile.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.bukkit.entity.projectile; + +import net.momirealms.craftengine.bukkit.entity.BukkitEntity; +import net.momirealms.craftengine.core.entity.projectile.Projectile; + +public class BukkitProjectile extends BukkitEntity implements Projectile { + + public BukkitProjectile(org.bukkit.entity.Projectile entity) { + super(entity); + } +} 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 new file mode 100644 index 000000000..371a024c6 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -0,0 +1,81 @@ +package net.momirealms.craftengine.bukkit.entity.projectile; + +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; +import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; +import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; +import net.momirealms.craftengine.core.item.Item; +import org.bukkit.Bukkit; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.ThrowableProjectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityRemoveEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class BukkitProjectileManager implements Listener, ProjectileManager { + private static BukkitProjectileManager instance; + private final BukkitCraftEngine plugin; + private final Map projectiles; + + public BukkitProjectileManager(BukkitCraftEngine plugin) { + this.plugin = plugin; + this.projectiles = new ConcurrentHashMap<>(); + instance = this; + } + + @Override + public void delayedInit() { + Bukkit.getPluginManager().registerEvents(this, this.plugin.bootstrap()); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); + } + + @Override + public Optional projectileByEntityId(int entityId) { + return Optional.ofNullable(this.projectiles.get(entityId)); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onProjectileLaunch(ProjectileLaunchEvent event) { + Projectile projectile = event.getEntity(); + ItemStack projectileItem; + if (projectile instanceof ThrowableProjectile throwableProjectile) { + projectileItem = throwableProjectile.getItem(); + } else if (projectile instanceof Arrow arrow) { + projectileItem = arrow.getItemStack(); + } else { + return; + } + System.out.println("发射"); + Item wrapped = this.plugin.itemManager().wrap(projectileItem); + if (wrapped == null) return; + wrapped.getCustomItem().ifPresent(it -> { + ProjectileMeta meta = it.settings().projectileMeta(); + if (meta != null) { + System.out.println("来啦"); + this.projectiles.put(projectile.getEntityId(), new BukkitCustomProjectile(meta, projectile, wrapped)); + } + }); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onEntityRemove(EntityRemoveEvent event) { + this.projectiles.remove(event.getEntity().getEntityId()); + } + + public static BukkitProjectileManager instance() { + return instance; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java index bc5e9772f..461ab6689 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java @@ -23,12 +23,16 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.ThrowableProjectile; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 6d63a4cd7..499c2cd36 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; +import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors; @@ -165,6 +166,7 @@ public class BukkitCraftEngine extends CraftEngine { super.vanillaLootManager = new BukkitVanillaLootManager(this); super.fontManager = new BukkitFontManager(this); super.advancementManager = new BukkitAdvancementManager(this); + super.projectileManager = new BukkitProjectileManager(this); super.onPluginEnable(); super.compatibilityManager().onEnable(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 2dc46a53d..e31773b82 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -43,7 +43,7 @@ public class TestCommand extends BukkitCommandFeature { })) .required("displayType", ByteParser.byteParser((byte) 0, (byte) 8)) .required("translation", StringParser.stringParser()) - .required("rotationLeft", StringParser.stringParser()) + .required("rotation", StringParser.stringParser()) .handler(context -> { Player player = context.sender(); NamespacedKey namespacedKey = context.get("id"); 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 7aae1ac37..fa78617ab 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 @@ -12,15 +12,13 @@ import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; -import net.momirealms.craftengine.bukkit.plugin.network.handler.ArmorStandPacketHandler; -import net.momirealms.craftengine.bukkit.plugin.network.handler.BlockDisplayPacketHandler; -import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; -import net.momirealms.craftengine.bukkit.plugin.network.handler.TextDisplayPacketHandler; +import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -1593,9 +1591,9 @@ public class PacketConsumers { public static final TriConsumer ADD_ENTITY = (user, event, packet) -> { try { Object entityType = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$type(packet); + int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); if (entityType == Reflections.instance$EntityType$ITEM_DISPLAY) { // Furniture - int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(furniture.fakeEntityIds())); @@ -1606,11 +1604,16 @@ public class PacketConsumers { } } else if (entityType == BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE) { // Cancel collider entity packet - int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { event.setCancelled(true); + user.entityPacketHandlers().put(entityId, FurnitureCollisionPacketHandler.INSTANCE); } + } else { + BukkitProjectileManager.instance().projectileByEntityId(entityId).ifPresent(customProjectile -> { + event.replacePacket(ProjectilePacketHandler.convertAddCustomProjectPacket(packet)); + user.entityPacketHandlers().put(entityId, new ProjectilePacketHandler(customProjectile)); + }); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); @@ -1621,8 +1624,9 @@ public class PacketConsumers { public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleSyncEntityPosition(user, event, packet); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityPositionSyncPacket", e); @@ -2214,7 +2218,10 @@ public class PacketConsumers { public static final TriConsumer MOVE_AND_ROTATE_ENTITY = (user, event, packet) -> { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); - + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMoveAndRotate(user, event, packet); + } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", 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..70121b19b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java @@ -0,0 +1,14 @@ +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); + } +} 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..f9f0134a6 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,9 @@ public class FurniturePacketHandler implements EntityPacketHandler { entityIds.addAll(this.fakeEntities); return true; } + + @Override + public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java similarity index 60% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 487fa4152..329ea6019 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CustomTridentPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -3,70 +3,61 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.core.entity.CustomTrident; +import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; +import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +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 net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Trident; import org.bukkit.inventory.ItemStack; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; -public final class CustomTridentPacketHandler { +public class ProjectilePacketHandler implements EntityPacketHandler { + private final CustomProjectile projectile; - private CustomTridentPacketHandler() {} + public ProjectilePacketHandler(CustomProjectile projectile) { + this.projectile = projectile; + } - public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) { + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + List newPackedItems = convertCustomProjectileSetEntityDataPacket(packedItems); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf); + } + + @Override + public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object converted = convertCustomProjectilePositionSyncPacket(packet); + event.replacePacket(converted); + } + + @Override + public void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object converted = convertCustomProjectileMovePacket(packet); + event.replacePacket(converted); + } + + public static Object convertAddCustomProjectPacket(Object packet) { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); - Trident trident = getTridentById(user, entityId); - if (trident == null) return; - World world = trident.getWorld(); - Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(trident); - Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); - Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); - if (notCustomTrident(trident)) return; - Object newPacket = modifyCustomTridentPacket(packet, entityId); - List itemDisplayValues = buildEntityDataValues(trident); - user.sendPacket(newPacket, true); - user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true); - event.setCancelled(true); - if (serverEntity != null) { - } - } - - private static boolean canSpawnParticle(Object nmsEntity) { - if (!FastNMS.INSTANCE.field$AbstractArrow$wasTouchingWater(nmsEntity)) return false; - return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); - } - - @Nullable - public static Trident getTridentById(NetWorkUser user, int entityId) { - Player player = (Player) user.platformPlayer(); - Entity entity = FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId); - if (entity instanceof Trident trident) return trident; - return null; - } - - public static boolean notCustomTrident(Trident trident) { - if (trident == null) return true; - Optional> customItem = BukkitItemManager.instance().wrap(trident.getItemStack()).getCustomItem(); - return customItem.map(itemStackCustomItem -> itemStackCustomItem.settings().customTrident() == null).orElse(true); - } - - public static Object modifyCustomTridentPacket(Object packet, int entityId) { UUID uuid = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$uuid(packet); double x = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$x(packet); double y = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$y(packet); @@ -86,29 +77,8 @@ public final class CustomTridentPacketHandler { ); } - public static List buildEntityDataValues(Trident trident) { - List itemDisplayValues = new ArrayList<>(); - ItemStack itemStack = trident.getItemStack(); - Optional> customItem = BukkitItemManager.instance().wrap(itemStack).getCustomItem(); - if (customItem.isEmpty()) return itemDisplayValues; - CustomTrident customTrident = customItem.get().settings().customTrident(); - Item item = BukkitItemManager.instance().createWrappedItem(customTrident.customTridentItemId(), null); - itemStack.getEnchantments().forEach((enchantment, level) -> item.addEnchantment(new Enchantment(Key.of(enchantment.getKey().toString()), level))); - ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(-1, itemDisplayValues); - ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(customTrident.translation(), itemDisplayValues); - ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(customTrident.rotationLefts(), itemDisplayValues); - if (VersionHelper.isOrAbove1_20_2()) { - ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); - ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); - } else { - ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); - } - ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(customTrident.displayType(), itemDisplayValues); - return itemDisplayValues; - } - - public static Object buildCustomTridentPositionSync(Object packet, int entityId) { + private Object convertCustomProjectilePositionSyncPacket(Object packet) { + int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); Object positionMoveRotation = FastNMS.INSTANCE.field$ClientboundEntityPositionSyncPacket$values(packet); boolean onGround = FastNMS.INSTANCE.field$ClientboundEntityPositionSyncPacket$onGround(packet); Object position = FastNMS.INSTANCE.field$PositionMoveRotation$position(positionMoveRotation); @@ -119,7 +89,43 @@ public final class CustomTridentPacketHandler { return FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(entityId, newPositionMoveRotation, onGround); } - public static Object buildCustomTridentMove(Object packet, int entityId) { + // 将原有的投掷物的entity data转化为展示实体的数据包 + public List convertCustomProjectileSetEntityDataPacket(List packedItems) { + List newPackedItems = new ArrayList<>(); + for (Object packedItem : packedItems) { + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId < 8) { + newPackedItems.add(packedItem); + } + } + newPackedItems.addAll(createCustomProjectileEntityDataValues()); + return newPackedItems; + } + + private List createCustomProjectileEntityDataValues() { + List itemDisplayValues = new ArrayList<>(); + Optional> customItem = BukkitItemManager.instance().getCustomItem(this.projectile.metadata().item()); + if (customItem.isEmpty()) return itemDisplayValues; + ProjectileMeta meta = projectile.metadata(); + Item displayedItem = customItem.get().buildItem(ItemBuildContext.EMPTY); + // 我们应当使用新的展示物品的组件覆盖原物品的组件,以完成附魔,附魔光效等组件的继承 + displayedItem = this.projectile.item().mergeCopy(displayedItem); + ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(-1, itemDisplayValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(meta.translation(), itemDisplayValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(meta.rotation(), itemDisplayValues); + if (VersionHelper.isOrAbove1_20_2()) { + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + } else { + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + } + ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(displayedItem.getLiteralObject(), itemDisplayValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(meta.displayType().id(), itemDisplayValues); + return itemDisplayValues; + } + + private static Object convertCustomProjectileMovePacket(Object packet) { + int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); short xa = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xa(packet); short ya = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$ya(packet); short za = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$za(packet); @@ -132,15 +138,4 @@ public final class CustomTridentPacketHandler { onGround ); } - - public static List buildCustomTridentSetEntityDataPacket(NetWorkUser user, List packedItems, int entityId) { - List newPackedItems = new ArrayList<>(); - for (Object packedItem : packedItems) { - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId < 8) { - newPackedItems.add(packedItem); - } - } - return newPackedItems; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index e401be613..dc8c5aeba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -3,7 +3,8 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Particle; -public class ParticleUtils { +public final class ParticleUtils { + private ParticleUtils() {} public static Particle getParticle(String particle) { try { @@ -12,9 +13,12 @@ public class ParticleUtils { return switch (particle) { case "REDSTONE" -> Particle.valueOf("DUST"); case "VILLAGER_HAPPY", "HAPPY_VILLAGER" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY"); - case "BUBBLE" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "BUBBLE" : "WATER_BUBBLE"); + case "BUBBLE", "WATER_BUBBLE" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "BUBBLE" : "WATER_BUBBLE"); default -> Particle.valueOf(particle); }; } } + + public static final Particle HAPPY_VILLAGER = getParticle("HAPPY_VILLAGER"); + public static final Particle BUBBLE = getParticle("BUBBLE"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java new file mode 100644 index 000000000..ae64546e9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.entity; + +import net.momirealms.craftengine.core.world.Vec3d; + +public abstract class AbstractEntity implements Entity { + + @Override + public Vec3d position() { + return new Vec3d(x(), y(), z()); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Billboard.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Billboard.java similarity index 80% rename from core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Billboard.java rename to core/src/main/java/net/momirealms/craftengine/core/entity/Billboard.java index 16545019d..7533b658b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Billboard.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Billboard.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.entity.furniture; +package net.momirealms.craftengine.core.entity; public enum Billboard { FIXED(0), diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java b/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java deleted file mode 100644 index aed870c82..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/CustomTrident.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.entity; - -import net.momirealms.craftengine.core.util.Key; -import org.joml.Quaternionf; -import org.joml.Vector3f; - -public record CustomTrident(Key customTridentItemId, Byte displayType, Vector3f translation, Quaternionf rotationLefts) { -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index 24efd4208..d1e4428e4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -5,31 +5,28 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; -public abstract class Entity { +public interface Entity { + Key type(); - public abstract Key type(); + double x(); - public abstract double x(); + double y(); - public abstract double y(); + double z(); - public abstract double z(); + Vec3d position(); - public Vec3d position() { - return new Vec3d(x(), y(), z()); - } + void tick(); - public abstract void tick(); + float getXRot(); - public abstract int entityID(); + int entityID(); - public abstract float getXRot(); + float getYRot(); - public abstract float getYRot(); + World world(); - public abstract World world(); + Direction getDirection(); - public abstract Direction getDirection(); - - public abstract Object literalObject(); + Object literalObject(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ItemDisplayContext.java b/core/src/main/java/net/momirealms/craftengine/core/entity/ItemDisplayContext.java similarity index 86% rename from core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ItemDisplayContext.java rename to core/src/main/java/net/momirealms/craftengine/core/entity/ItemDisplayContext.java index 2fbd54078..adbead883 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ItemDisplayContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/ItemDisplayContext.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.entity.furniture; +package net.momirealms.craftengine.core.entity; public enum ItemDisplayContext { NONE(0), diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java index 426907463..b2f4151f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.entity.furniture; +import net.momirealms.craftengine.core.entity.Billboard; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.util.Key; import org.joml.Quaternionf; import org.joml.Vector3f; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ExternalModel.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ExternalModel.java index 5a12ba446..8f2f1c4b1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ExternalModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/ExternalModel.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; public interface ExternalModel { @@ -8,5 +8,5 @@ public interface ExternalModel { String id(); - void bindModel(Entity entity); + void bindModel(AbstractEntity entity); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index b92b56dc5..3ed6f1449 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.entity.furniture; +import net.momirealms.craftengine.core.entity.Billboard; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import org.joml.Quaternionf; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 2655d6804..7dd60f33b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; @@ -31,7 +31,7 @@ public interface FurnitureManager extends Manageable { Furniture loadedFurnitureByRealEntityId(int entityId); @Nullable - default Furniture loadedFurnitureByRealEntity(Entity entity) { + default Furniture loadedFurnitureByRealEntity(AbstractEntity entity) { return loadedFurnitureByRealEntityId(entity.entityID()); } 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 48d6b6185..dccc2734f 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.entity.player; import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.Key; @@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -public abstract class Player extends Entity implements NetWorkUser { +public abstract class Player extends AbstractEntity implements NetWorkUser { private static final Key TYPE = Key.of("minecraft:player"); public abstract boolean isSecondaryUseActive(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/AbstractCustomProjectile.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/AbstractCustomProjectile.java new file mode 100644 index 000000000..117367a84 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/AbstractCustomProjectile.java @@ -0,0 +1,30 @@ +package net.momirealms.craftengine.core.entity.projectile; + +import net.momirealms.craftengine.core.item.Item; + +public abstract class AbstractCustomProjectile implements CustomProjectile { + protected final ProjectileMeta meta; + protected final Projectile projectile; + protected final Item item; + + protected AbstractCustomProjectile(ProjectileMeta meta, Projectile projectile, Item item) { + this.meta = meta; + this.projectile = projectile; + this.item = item; + } + + @Override + public ProjectileMeta metadata() { + return this.meta; + } + + @Override + public Projectile projectile() { + return projectile; + } + + @Override + public Item item() { + return item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/CustomProjectile.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/CustomProjectile.java new file mode 100644 index 000000000..661f2d4ac --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/CustomProjectile.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.entity.projectile; + +import net.momirealms.craftengine.core.item.Item; + +public interface CustomProjectile { + + ProjectileMeta metadata(); + + Projectile projectile(); + + Item item(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/Projectile.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/Projectile.java new file mode 100644 index 000000000..c721ee990 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/Projectile.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.entity.projectile; + +import net.momirealms.craftengine.core.entity.Entity; + +public interface Projectile extends Entity { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileManager.java new file mode 100644 index 000000000..12796743a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileManager.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.entity.projectile; + +import net.momirealms.craftengine.core.plugin.Manageable; + +import java.util.Optional; + +public interface ProjectileManager extends Manageable { + + Optional projectileByEntityId(int entityId); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java new file mode 100644 index 000000000..8ca3ec0b1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.entity.projectile; + +import net.momirealms.craftengine.core.entity.ItemDisplayContext; +import net.momirealms.craftengine.core.util.Key; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f translation, Quaternionf rotation) { +} 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 d9968d902..3b9a5bc07 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item; -import net.momirealms.craftengine.core.entity.CustomTrident; +import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.item.modifier.EquippableModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; @@ -25,7 +26,7 @@ public class ItemSettings { List anvilRepairItems = List.of(); boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; - CustomTrident customTrident; + ProjectileMeta projectileMeta; private ItemSettings() {} @@ -54,7 +55,7 @@ public class ItemSettings { newSettings.anvilRepairItems = settings.anvilRepairItems; newSettings.renameable = settings.renameable; newSettings.canPlaceRelatedVanillaBlock = settings.canPlaceRelatedVanillaBlock; - newSettings.customTrident = settings.customTrident; + newSettings.projectileMeta = settings.projectileMeta; return newSettings; } @@ -70,8 +71,8 @@ public class ItemSettings { return settings; } - public CustomTrident customTrident() { - return customTrident; + public ProjectileMeta projectileMeta() { + return projectileMeta; } public boolean canPlaceRelatedVanillaBlock() { @@ -118,8 +119,8 @@ public class ItemSettings { return this; } - public ItemSettings customTrident(CustomTrident customTrident) { - this.customTrident = customTrident; + public ItemSettings projectileMeta(ProjectileMeta projectileMeta) { + this.projectileMeta = projectileMeta; return this; } @@ -207,13 +208,13 @@ public class ItemSettings { boolean bool = (boolean) value; return settings -> settings.canPlaceRelatedVanillaBlock(bool); })); - registerFactory("custom-trident", (value -> { + registerFactory("projectile", (value -> { Map args = MiscUtils.castToMap(value, false); - Key customTridentItemId = Key.of(args.get("custom-trident-item").toString()); - Byte displayType = Byte.valueOf(args.get("display-type").toString()); + Key customTridentItemId = Key.of(Objects.requireNonNull(args.get("item"), "'item should not be null'").toString()); + ItemDisplayContext displayType = ItemDisplayContext.valueOf(args.getOrDefault("display-transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); Vector3f translation = MiscUtils.getAsVector3f(args.get("translation"), "translation"); Quaternionf rotationLefts = MiscUtils.getAsQuaternionf(args.get("rotation-left"), "rotation-left"); - return settings -> settings.customTrident(new CustomTrident(customTridentItemId, displayType, translation, rotationLefts)); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, translation, rotationLefts)); })); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 51e975b79..59d86f55d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.advancement.AdvancementManager; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; +import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; @@ -70,6 +71,7 @@ public abstract class CraftEngine implements Plugin { protected AdvancementManager advancementManager; protected CompatibilityManager compatibilityManager; protected GlobalVariableManager globalVariableManager; + protected ProjectileManager projectileManager; private final Consumer reloadEventDispatcher; private boolean isReloading; @@ -147,6 +149,7 @@ public abstract class CraftEngine implements Plugin { this.guiManager.reload(); this.packManager.reload(); this.advancementManager.reload(); + this.projectileManager.reload(); if (reloadRecipe) { this.recipeManager.reload(); } @@ -218,6 +221,7 @@ public abstract class CraftEngine implements Plugin { this.fontManager.delayedInit(); this.vanillaLootManager.delayedInit(); this.advancementManager.delayedInit(); + this.projectileManager.delayedInit(); // reload the plugin try { this.reloadPlugin(Runnable::run, Runnable::run, true); @@ -250,6 +254,7 @@ public abstract class CraftEngine implements Plugin { if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); if (this.translationManager != null) this.translationManager.disable(); if (this.globalVariableManager != null) this.globalVariableManager.disable(); + if (this.projectileManager != null) this.projectileManager.disable(); if (this.scheduler != null) this.scheduler.shutdownScheduler(); if (this.scheduler != null) this.scheduler.shutdownExecutor(); if (this.commandManager != null) this.commandManager.unregisterFeatures(); @@ -442,6 +447,11 @@ public abstract class CraftEngine implements Plugin { return globalVariableManager; } + @Override + public ProjectileManager projectileManager() { + return projectileManager; + } + @Override public Platform platform() { return platform; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index 1dde1374e..cbb4feb74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.advancement.AdvancementManager; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; +import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; @@ -94,5 +95,7 @@ public interface Plugin { GlobalVariableManager globalVariableManager(); + ProjectileManager projectileManager(); + Platform platform(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java index c3a17484f..4e7efd8e3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.plugin.context.parameter; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.ContextKey; @@ -17,10 +17,10 @@ import java.util.function.Function; public class PlayerParameterProvider implements LazyContextParameterProvider { private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { - CONTEXT_FUNCTIONS.put(PlayerParameters.X, Entity::x); - CONTEXT_FUNCTIONS.put(PlayerParameters.Y, Entity::y); - CONTEXT_FUNCTIONS.put(PlayerParameters.Z, Entity::z); - CONTEXT_FUNCTIONS.put(PlayerParameters.POS, Entity::position); + CONTEXT_FUNCTIONS.put(PlayerParameters.X, AbstractEntity::x); + CONTEXT_FUNCTIONS.put(PlayerParameters.Y, AbstractEntity::y); + CONTEXT_FUNCTIONS.put(PlayerParameters.Z, AbstractEntity::z); + CONTEXT_FUNCTIONS.put(PlayerParameters.POS, AbstractEntity::position); CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); 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 8a2c9e78e..224a27f81 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 @@ -10,4 +10,10 @@ public interface EntityPacketHandler { default void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { } + + default void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { + } + + default void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java index a55f7047c..87cd8df73 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.util; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.world.Vec3i; import org.jetbrains.annotations.Nullable; @@ -93,7 +93,7 @@ public enum Direction { }; } - public static Direction[] orderedByNearest(Entity entity) { + public static Direction[] orderedByNearest(AbstractEntity entity) { float xRotation = entity.getXRot() * (float) (Math.PI / 180.0); float yRotation = -entity.getYRot() * (float) (Math.PI / 180.0); float sinX = (float) Math.sin(xRotation); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/HitResult.java b/core/src/main/java/net/momirealms/craftengine/core/world/HitResult.java index 4c1d08e71..a7a4aae69 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/HitResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/HitResult.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.world; -import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.entity.AbstractEntity; public abstract class HitResult { protected final Vec3d location; @@ -9,7 +9,7 @@ public abstract class HitResult { this.location = pos; } - public double distanceTo(Entity entity) { + public double distanceTo(AbstractEntity entity) { double d = this.location.x() - entity.x(); double e = this.location.y() - entity.y(); double f = this.location.z() - entity.z(); From 593f3021a7c091be1caafc3310f01f744ffdae2e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 00:49:32 +0800 Subject: [PATCH 30/73] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=BC=B9=E5=B0=84=E7=89=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureElement.java | 2 +- .../projectile/BukkitProjectileManager.java | 65 +++++++++++++++++-- .../bukkit/item/ItemEventListener.java | 4 -- .../plugin/network/BukkitNetworkManager.java | 4 +- .../plugin/network/PacketConsumers.java | 29 +++++---- .../handler/ProjectilePacketHandler.java | 52 ++++++--------- .../craftengine/bukkit/util/Reflections.java | 11 ++++ .../craftengine/core/item/ItemSettings.java | 2 +- 8 files changed, 109 insertions(+), 60 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index ec41936ac..044034209 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -4,9 +4,9 @@ import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; +import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; 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 371a024c6..6e1d51452 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 @@ -1,25 +1,31 @@ package net.momirealms.craftengine.bukkit.entity.projectile; +import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Arrow; +import org.bukkit.entity.Entity; import org.bukkit.entity.Projectile; import org.bukkit.entity.ThrowableProjectile; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityRemoveEvent; import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.inventory.ItemStack; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class BukkitProjectileManager implements Listener, ProjectileManager { private static BukkitProjectileManager instance; @@ -50,6 +56,24 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onProjectileLaunch(ProjectileLaunchEvent event) { Projectile projectile = event.getEntity(); + handleProjectileLoad(projectile, true); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntitiesLoad(EntitiesLoadEvent event) { + for (Entity entity : event.getEntities()) { + if (entity instanceof Projectile projectile) { + handleProjectileLoad(projectile, false); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onEntityRemove(EntityRemoveFromWorldEvent event) { + this.projectiles.remove(event.getEntity().getEntityId()); + } + + private void handleProjectileLoad(Projectile projectile, boolean delay) { ItemStack projectileItem; if (projectile instanceof ThrowableProjectile throwableProjectile) { projectileItem = throwableProjectile.getItem(); @@ -58,21 +82,50 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { } else { return; } - System.out.println("发射"); Item wrapped = this.plugin.itemManager().wrap(projectileItem); if (wrapped == null) return; wrapped.getCustomItem().ifPresent(it -> { ProjectileMeta meta = it.settings().projectileMeta(); if (meta != null) { - System.out.println("来啦"); this.projectiles.put(projectile.getEntityId(), new BukkitCustomProjectile(meta, projectile, wrapped)); + ProjectileInjectTask task = new ProjectileInjectTask(projectile); + if (!delay) { + task.run(); + } else if (VersionHelper.isFolia()) { + projectile.getScheduler().run(plugin.bootstrap(), (t) -> task.run(), () -> {}); + } else { + plugin.scheduler().sync().runDelayed(task); + } } }); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) - public void onEntityRemove(EntityRemoveEvent event) { - this.projectiles.remove(event.getEntity().getEntityId()); + public class ProjectileInjectTask implements Runnable { + private final Projectile projectile; + + public ProjectileInjectTask(Projectile projectile) { + this.projectile = projectile; + } + + @Override + public void run() { + Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile); + Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); + if (trackedEntity == null) { + plugin.logger().warn("Failed to update server entity tracking interval due to missing tracked entity"); + return; + } + Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); + if (serverEntity == null) { + plugin.logger().warn("Failed to update server entity tracking interval due to missing server entity"); + return; + } + try { + Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1); + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to update server entity tracking interval", e); + } + } } public static BukkitProjectileManager instance() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java index 461ab6689..bc5e9772f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java @@ -23,16 +23,12 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.ThrowableProjectile; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; 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 cf568a561..d5998aed6 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 @@ -139,7 +139,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.RESPAWN, Reflections.clazz$ClientboundRespawnPacket); registerNMSPacketConsumer(PacketConsumers.INTERACT_ENTITY, Reflections.clazz$ServerboundInteractPacket); registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, Reflections.clazz$ClientboundEntityPositionSyncPacket); - registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos); + registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos); registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, Reflections.clazz$ServerboundPickItemFromEntityPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket); @@ -150,7 +150,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket); registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); - registerNMSPacketConsumer(PacketConsumers.MOVE_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(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 fa78617ab..dd0c37492 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 @@ -1611,8 +1611,9 @@ public class PacketConsumers { } } else { BukkitProjectileManager.instance().projectileByEntityId(entityId).ifPresent(customProjectile -> { - event.replacePacket(ProjectilePacketHandler.convertAddCustomProjectPacket(packet)); - user.entityPacketHandlers().put(entityId, new ProjectilePacketHandler(customProjectile)); + ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, entityId); + event.replacePacket(handler.convertAddCustomProjectilePacket(packet)); + user.entityPacketHandlers().put(entityId, handler); }); } } catch (Exception e) { @@ -1633,17 +1634,6 @@ public class PacketConsumers { } }; - public static final TriConsumer MOVE_ENTITY = (user, event, packet) -> { - try { - int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$Pos", e); - } - }; - public static final BiConsumer REMOVE_ENTITY = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); @@ -2215,7 +2205,18 @@ public class PacketConsumers { } }; - public static final TriConsumer MOVE_AND_ROTATE_ENTITY = (user, event, packet) -> { + public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { + try { + int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); + } + }; + + public static final TriConsumer MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> { try { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 329ea6019..b5f5d1cc4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -26,22 +26,24 @@ import java.util.UUID; public class ProjectilePacketHandler implements EntityPacketHandler { private final CustomProjectile projectile; + private final Object cachedPacket; + private final List cachedData; - public ProjectilePacketHandler(CustomProjectile projectile) { + public ProjectilePacketHandler(CustomProjectile projectile, int entityId) { this.projectile = projectile; + this.cachedData = createCustomProjectileEntityDataValues(); + this.cachedPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, this.cachedData); } @Override public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - List newPackedItems = convertCustomProjectileSetEntityDataPacket(packedItems); event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(this.cachedData, buf); } @Override @@ -52,11 +54,15 @@ public class ProjectilePacketHandler implements EntityPacketHandler { @Override public void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { - Object converted = convertCustomProjectileMovePacket(packet); - event.replacePacket(converted); + int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); + Object converted = convertCustomProjectileMovePacket(packet, entityId); + event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of( + this.cachedPacket, + converted + ))); } - public static Object convertAddCustomProjectPacket(Object packet) { + public Object convertAddCustomProjectilePacket(Object packet) { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); UUID uuid = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$uuid(packet); double x = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$x(packet); @@ -70,11 +76,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler { double ya = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$ya(packet); double za = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$za(packet); double yHeadRot = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$yHeadRot(packet); - return FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId, uuid, x, y, z, - MCUtils.clamp(-xRot, -90.0F, 90.0F), -yRot, - type, data, FastNMS.INSTANCE.constructor$Vec3(xa, ya, za), yHeadRot - ); + return FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(entityId, uuid, x, y, z, MCUtils.clamp(-xRot, -90.0F, 90.0F), -yRot, type, data, FastNMS.INSTANCE.constructor$Vec3(xa, ya, za), yHeadRot); } private Object convertCustomProjectilePositionSyncPacket(Object packet) { @@ -89,24 +91,11 @@ public class ProjectilePacketHandler implements EntityPacketHandler { return FastNMS.INSTANCE.constructor$ClientboundEntityPositionSyncPacket(entityId, newPositionMoveRotation, onGround); } - // 将原有的投掷物的entity data转化为展示实体的数据包 - public List convertCustomProjectileSetEntityDataPacket(List packedItems) { - List newPackedItems = new ArrayList<>(); - for (Object packedItem : packedItems) { - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId < 8) { - newPackedItems.add(packedItem); - } - } - newPackedItems.addAll(createCustomProjectileEntityDataValues()); - return newPackedItems; - } - - private List createCustomProjectileEntityDataValues() { + public List createCustomProjectileEntityDataValues() { List itemDisplayValues = new ArrayList<>(); Optional> customItem = BukkitItemManager.instance().getCustomItem(this.projectile.metadata().item()); if (customItem.isEmpty()) return itemDisplayValues; - ProjectileMeta meta = projectile.metadata(); + ProjectileMeta meta = this.projectile.metadata(); Item displayedItem = customItem.get().buildItem(ItemBuildContext.EMPTY); // 我们应当使用新的展示物品的组件覆盖原物品的组件,以完成附魔,附魔光效等组件的继承 displayedItem = this.projectile.item().mergeCopy(displayedItem); @@ -114,18 +103,17 @@ public class ProjectilePacketHandler implements EntityPacketHandler { ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(meta.translation(), itemDisplayValues); ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(meta.rotation(), itemDisplayValues); if (VersionHelper.isOrAbove1_20_2()) { - ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); - ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues); + ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues); } else { - ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(2, itemDisplayValues); + ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues); } ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(displayedItem.getLiteralObject(), itemDisplayValues); ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(meta.displayType().id(), itemDisplayValues); return itemDisplayValues; } - private static Object convertCustomProjectileMovePacket(Object packet) { - int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); + private Object convertCustomProjectileMovePacket(Object packet, int entityId) { short xa = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xa(packet); short ya = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$ya(packet); short za = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$za(packet); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 1ab0294db..4e5515cd3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6634,4 +6634,15 @@ public class Reflections { ) ); + public static final Class clazz$ServerEntity = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "server.level.EntityTrackerEntry", + "server.level.ServerEntity") + ); + + public static final Field field$ServerEntity$updateInterval = requireNonNull( + ReflectionUtils.getInstanceDeclaredField( + clazz$ServerEntity, int.class, 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 3b9a5bc07..ff5b725e8 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item; -import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.entity.ItemDisplayContext; +import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.modifier.EquippableModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; From a87a5ef7dec4165d44d78545df940026b6b1e932 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 01:11:38 +0800 Subject: [PATCH 31/73] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E7=B2=92=E5=AD=90?= =?UTF-8?q?=E6=95=88=E6=9E=9C=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectile/BukkitProjectileManager.java | 53 ++++++++++++++----- .../craftengine/bukkit/util/Reflections.java | 7 +++ gradle.properties | 2 +- 3 files changed, 48 insertions(+), 14 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 6e1d51452..e899169c2 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 @@ -3,13 +3,17 @@ package net.momirealms.craftengine.bukkit.entity.projectile; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask; +import net.momirealms.craftengine.bukkit.util.ParticleUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; +import org.bukkit.Particle; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.Projectile; @@ -92,7 +96,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { if (!delay) { task.run(); } else if (VersionHelper.isFolia()) { - projectile.getScheduler().run(plugin.bootstrap(), (t) -> task.run(), () -> {}); + } else { plugin.scheduler().sync().runDelayed(task); } @@ -102,29 +106,52 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { public class ProjectileInjectTask implements Runnable { private final Projectile projectile; + private final SchedulerTask task; + private boolean injected; public ProjectileInjectTask(Projectile projectile) { this.projectile = projectile; + if (VersionHelper.isFolia()) { + this.task = new FoliaTask(projectile.getScheduler().runAtFixedRate(plugin.bootstrap(), (t) -> this.run(), () -> {}, 1, 1)); + } else { + this.task = plugin.scheduler().sync().runRepeating(this, 1, 1); + } } @Override public void run() { + if (!this.projectile.isValid()) { + this.task.cancel(); + return; + } Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile); - Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); - if (trackedEntity == null) { - plugin.logger().warn("Failed to update server entity tracking interval due to missing tracked entity"); - return; + if (!this.injected) { + Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); + if (trackedEntity == null) { + return; + } + Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); + if (serverEntity == null) { + return; + } + try { + Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1); + this.injected = true; + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to update server entity tracking interval", e); + } } - Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); - if (serverEntity == null) { - plugin.logger().warn("Failed to update server entity tracking interval due to missing server entity"); - return; + if (canSpawnParticle(nmsEntity)) { + this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0); } - try { - Reflections.field$ServerEntity$updateInterval.set(serverEntity, 1); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to update server entity tracking interval", e); + } + + private static boolean canSpawnParticle(Object nmsEntity) { + if (!FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) return false; + if (Reflections.clazz$AbstractArrow.isInstance(nmsEntity)) { + return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); } + return true; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 4e5515cd3..64f6096c4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6645,4 +6645,11 @@ public class Reflections { clazz$ServerEntity, int.class, 0 ) ); + + public static final Class clazz$AbstractArrow = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.EntityArrow", + "world.entity.projectile.AbstractArrow" + ) + ); } diff --git a/gradle.properties b/gradle.properties index 9acb04c0c..d4e994cdc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.17 +nms_helper_version=0.65.18 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 7039f33396260aa653448d2ca6dcd98da4e062a3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 03:31:31 +0800 Subject: [PATCH 32/73] =?UTF-8?q?=E5=BC=B9=E5=B0=84=E7=89=A9=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/categories.yml | 1 + .../resources/default/configuration/i18n.yml | 2 + .../resources/default/configuration/items.yml | 45 +++++++- .../custom/ender_pearl_flower_stage_3.json | 43 -------- .../item/custom/topaz_trident_in_hand.json | 94 +++++++++++++++++ .../item/custom/topaz_trident_throwing.json | 96 ++++++++++++++++++ .../custom/ender_pearl_flower_stage_3.png | Bin 362 -> 0 bytes .../textures/item/custom/topaz_trident.png | Bin 0 -> 231 bytes .../textures/item/custom/topaz_trident_3d.png | Bin 0 -> 548 bytes .../projectile/BukkitProjectileManager.java | 15 +-- .../handler/ProjectilePacketHandler.java | 1 + .../entity/projectile/ProjectileMeta.java | 2 +- .../craftengine/core/item/ItemSettings.java | 7 +- .../core/pack/AbstractPackManager.java | 4 + .../craftengine/core/util/MiscUtils.java | 37 ++++--- gradle.properties | 2 +- 16 files changed, 275 insertions(+), 74 deletions(-) delete mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json delete mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident_3d.png diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index 3189f43a4..fd442e990 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -38,6 +38,7 @@ categories: - default:topaz_bow - default:topaz_crossbow - default:topaz_rod + - default:topaz_trident - default:topaz_helmet - default:topaz_chestplate - default:topaz_leggings diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index fe6db7c36..99e6d9705 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -20,6 +20,7 @@ i18n: item.topaz_chestplate: "Topaz Chestplate" item.topaz_leggings: "Topaz Leggings" item.topaz_boots: "Topaz Boots" + item.topaz_trident: "Topaz Trident" item.topaz_ore: "Topaz Ore" item.deepslate_topaz_ore: "Deepslate Topaz Ore" item.topaz: "Topaz" @@ -63,6 +64,7 @@ i18n: item.topaz_chestplate: "黄玉胸甲" item.topaz_leggings: "黄玉护腿" item.topaz_boots: "黄玉靴子" + item.topaz_trident: "黄玉三叉戟" item.topaz_ore: "黄玉矿石" item.deepslate_topaz_ore: "深层黄玉矿石" item.topaz: "黄玉" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml index b21baa96f..923daec69 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml @@ -175,7 +175,42 @@ items#topaz_gears: arguments: part: boots slot: feet - + default:topaz_trident: + material: trident + custom-model-data: 1000 + settings: + projectile: + item: default:topaz_trident + translation: 0,0,0 + rotation: 1,1,1,1 + display-transform: NONE + scale: 0.5 + tags: + - "default:topaz_tools" + data: + item-name: "<#FF8C00>" + tooltip-style: minecraft:topaz + model: + type: minecraft:select + property: minecraft:display_context + cases: + - when: ["gui", "ground", "fixed"] + model: + type: minecraft:model + path: minecraft:item/custom/topaz_trident + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/topaz_trident + fallback: + type: minecraft:condition + property: minecraft:using_item + on-true: + type: minecraft:model + path: minecraft:item/custom/topaz_trident_throwing + on-false: + type: minecraft:model + path: minecraft:item/custom/topaz_trident_in_hand templates: default:armor/topaz: material: "chainmail_{part}" @@ -428,4 +463,12 @@ recipes#11: template-type: default:topaz result: id: default:topaz_rod + count: 1 + default:topaz_trident: + type: smithing_transform + base: minecraft:trident + addition: default:topaz + template-type: default:topaz + result: + id: default:topaz_trident count: 1 \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json deleted file mode 100644 index c65bc426f..000000000 --- a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "ambientocclusion": false, - "textures": { - "1": "item/ender_pearl", - "particle": "block/custom/ender_pearl_flower_stage_3", - "cross": "block/custom/ender_pearl_flower_stage_3" - }, - "elements": [ - { - "from": [0.8, 0, 8], - "to": [15.2, 16, 8], - "shade": false, - "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, - "faces": { - "north": {"uv": [0, 0, 16, 16], "texture": "#cross"}, - "south": {"uv": [0, 0, 16, 16], "texture": "#cross"} - } - }, - { - "from": [8, 0, 0.8], - "to": [8, 16, 15.2], - "shade": false, - "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, - "faces": { - "east": {"uv": [0, 0, 16, 16], "texture": "#cross"}, - "west": {"uv": [0, 0, 16, 16], "texture": "#cross"} - } - }, - { - "from": [8, 5, -1], - "to": [8, 21, 15], - "rotation": {"angle": 0, "axis": "y", "origin": [7, 5, 7]}, - "faces": { - "north": {"uv": [0, 0, 0, 16], "texture": "#1"}, - "east": {"uv": [0, 0, 16, 16], "texture": "#1"}, - "south": {"uv": [0, 0, 0, 16], "texture": "#1"}, - "west": {"uv": [0, 0, 16, 16], "texture": "#1"}, - "up": {"uv": [0, 0, 0, 16], "texture": "#1"}, - "down": {"uv": [0, 0, 0, 16], "texture": "#1"} - } - } - ] -} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json new file mode 100644 index 000000000..52fbb8b40 --- /dev/null +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json @@ -0,0 +1,94 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "item/custom/topaz_trident_3d", + "particle": "item/custom/topaz_trident_3d" + }, + "elements": [ + { + "from": [7.75, -5.5, 7.75], + "to": [8.25, 10, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "east": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "south": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "west": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "up": {"uv": [3, 0, 3.5, 0.5], "texture": "#0"}, + "down": {"uv": [0.5, 15.5, 1, 16], "texture": "#0"} + } + }, + { + "from": [7.25, 7, 7.75], + "to": [7.75, 8, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "east": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "south": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "west": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "up": {"uv": [11, 2.5, 11.5, 3], "texture": "#0"}, + "down": {"uv": [11, 3, 11.5, 3.5], "texture": "#0"} + } + }, + { + "from": [6.75, 7.5, 7.75], + "to": [7.25, 9.5, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "east": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "south": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "west": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "up": {"uv": [11.5, 1, 12, 1.5], "texture": "#0"}, + "down": {"uv": [11.5, 2.5, 12, 3], "texture": "#0"} + } + }, + { + "from": [8.75, 7.5, 7.75], + "to": [9.25, 9.5, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "east": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "south": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "west": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "up": {"uv": [11.5, 1, 12, 1.5], "texture": "#0"}, + "down": {"uv": [11.5, 2.5, 12, 3], "texture": "#0"} + } + }, + { + "from": [8.25, 7, 7.75], + "to": [8.75, 8, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "east": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "south": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "west": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "up": {"uv": [11, 2.5, 11.5, 3], "texture": "#0"}, + "down": {"uv": [11, 3, 11.5, 3.5], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [0, 60, 0], + "translation": [0.25, 9, 1.5], + "scale": [2, 2, 2] + }, + "thirdperson_lefthand": { + "rotation": [0, 60, 0], + "translation": [0.25, 9, 1.5], + "scale": [2, 2, 2] + }, + "firstperson_righthand": { + "rotation": [0, -90, 25], + "translation": [-2.5, 7.5, 4.75] + }, + "firstperson_lefthand": { + "rotation": [0, 90, -25], + "translation": [-2.5, 7.5, 4.75] + } + } +} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json new file mode 100644 index 000000000..fded0b6dc --- /dev/null +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "item/custom/topaz_trident_3d", + "particle": "item/custom/topaz_trident_3d" + }, + "elements": [ + { + "from": [7.75, -5.5, 7.75], + "to": [8.25, 10, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "east": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "south": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "west": {"uv": [10.5, 0.5, 11, 16], "texture": "#0"}, + "up": {"uv": [3, 0, 3.5, 0.5], "texture": "#0"}, + "down": {"uv": [0.5, 15.5, 1, 16], "texture": "#0"} + } + }, + { + "from": [7.25, 7, 7.75], + "to": [7.75, 8, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "east": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "south": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "west": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "up": {"uv": [11, 2.5, 11.5, 3], "texture": "#0"}, + "down": {"uv": [11, 3, 11.5, 3.5], "texture": "#0"} + } + }, + { + "from": [6.75, 7.5, 7.75], + "to": [7.25, 9.5, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "east": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "south": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "west": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "up": {"uv": [11.5, 1, 12, 1.5], "texture": "#0"}, + "down": {"uv": [11.5, 2.5, 12, 3], "texture": "#0"} + } + }, + { + "from": [8.75, 7.5, 7.75], + "to": [9.25, 9.5, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "east": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "south": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "west": {"uv": [11.5, 1, 12, 3], "texture": "#0"}, + "up": {"uv": [11.5, 1, 12, 1.5], "texture": "#0"}, + "down": {"uv": [11.5, 2.5, 12, 3], "texture": "#0"} + } + }, + { + "from": [8.25, 7, 7.75], + "to": [8.75, 8, 8.25], + "rotation": {"angle": 0, "axis": "y", "origin": [4, -5.5, 4]}, + "faces": { + "north": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "east": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "south": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "west": {"uv": [11, 2.5, 11.5, 3.5], "texture": "#0"}, + "up": {"uv": [11, 2.5, 11.5, 3], "texture": "#0"}, + "down": {"uv": [11, 3, 11.5, 3.5], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [0, 90, 180], + "translation": [0.25, -9, 1.5], + "scale": [2, 2, 2] + }, + "thirdperson_lefthand": { + "rotation": [0, 90, 180], + "translation": [0.25, -9, 1.5], + "scale": [2, 2, 2] + }, + "firstperson_righthand": { + "rotation": [0, -90, 25], + "translation": [0.75, -5, -0.75], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_lefthand": { + "rotation": [0, 90, -25], + "translation": [0.75, -5, -0.75], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png deleted file mode 100644 index 358b7874c5eb77c4525cd4422ed30fc4470ae8f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 362 zcmV-w0hRuVP)Px$BuPX;R5*?8ks(jRKp2Lf8@P!HT$^UOgrpL|e!xk70p>y`>nl(V2}$+*1fmJ$ zXTU-xnZQxiEKBPv>VQLCckM_B36f8K_rA~feec14{cSB5bF*B`&2Mz0;p2ER{c(`1 z8M(A5&P3a6Np#X}aesHy+bGeAd3*fa11!;nqiV_=mPJYak_$UfxWPO>ydy)|gIrvmQoMdJG><1!+Ge{C(XLb$C1p{P z=)_cYg*Y)iGr(>W&^BA5I1|GCHVe@+Z2)8_SwF4uJ)f$s@I4pmxlmGw#07*qo IM6N<$g2dsPWdHyG diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident.png new file mode 100644 index 0000000000000000000000000000000000000000..a4b1ec38cae59a399a21601f4270020574168442 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|7J9lkhFJ6_ zCoEu}VV3&yKL{-M_`Ggz`+s8t1A{lWDrZz2F36l`mTLKtZNl1_jg5^96}Er>|J0-H z|BG3j-;RM8|DS9B+b?snVc|}N?b9uo<4ivOt-pAr{gF`0*`6IH<&j2z`aeHOj@a^7 zm>CET8&8hgai`_vQH!q&Z`?^e=}>j&@E_YtCX;0oczAepZp#DhwfS)*piHKG$|Gim Yd2`ozmalE~06Lbz)78&qol`;+05r{JoB#j- literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident_3d.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident_3d.png new file mode 100644 index 0000000000000000000000000000000000000000..692a34f0fc504ecce5ac4d802631d4ec27a5fd5a GIT binary patch literal 548 zcmV+<0^9wGP)Px$-bqA3R9J=Wma$6$Q5?s=C$~g(p%6r9lxQJ>Gz22lSm9qF5wtW0Q3Q?+4h=#P zB!*MqVw00}bd3d4YePdB2Sy1^zHpRZgPojb>3i7e;s+i--s9f;eZRkVckclJN-sK9 z5(?o5E#@R5A}!{mWCYCy8*rpkIVzRP$h$Jou5U?;IVlvZV}JJqp9bz6&_GYC}fV^kRCTclK};vPYja*1$kEn zKEE3;&u{Sg-B?>+kwio!BcQFQf~?9AFQV&QS=9mPtkKgM#x@&H<`<^H98>Xmqd4wT`3LWWVvns@%`o zB0vOrT$!*8vAznhr2_4y{zewrFFUYh3q(xGulMDi6IyAQ;xi(9!>vCeA6QLw m6p&RL<;to|sC1nWG4c(*>I!4O-U0al0000 args = MiscUtils.castToMap(value, false); Key customTridentItemId = Key.of(Objects.requireNonNull(args.get("item"), "'item should not be null'").toString()); ItemDisplayContext displayType = ItemDisplayContext.valueOf(args.getOrDefault("display-transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); - Vector3f translation = MiscUtils.getAsVector3f(args.get("translation"), "translation"); - Quaternionf rotationLefts = MiscUtils.getAsQuaternionf(args.get("rotation-left"), "rotation-left"); - return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, translation, rotationLefts)); + Vector3f translation = MiscUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation"); + Vector3f scale = MiscUtils.getAsVector3f(args.getOrDefault("scale", "1"), "scale"); + Quaternionf rotation = MiscUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation-left", "rotation"), "rotation-left"); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation)); })); } 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 a4a02839d..df19992c8 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 @@ -347,6 +347,8 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_1.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_trident_3d.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid/topaz.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid_leggings/topaz.png"); for (String item : List.of("helmet", "chestplate", "leggings", "boots", "pickaxe", "axe", "sword", "hoe", "shovel")) { @@ -391,6 +393,8 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json"); // furniture plugin.saveResource("resources/default/configuration/furniture.yml"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json"); 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 c208c1c2f..b16bd6df5 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.util; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import org.joml.Quaternionf; import org.joml.Vector3f; +import software.amazon.awssdk.services.s3.endpoints.internal.Value; import java.util.ArrayList; import java.util.List; @@ -41,27 +42,35 @@ public class MiscUtils { public static Vector3f getAsVector3f(Object o, String option) { if (o == null) return new Vector3f(); - String stringFormat = o.toString(); - String[] split = stringFormat.split(","); - if (split.length == 3) { - return new Vector3f(Float.parseFloat(split[0]), Float.parseFloat(split[1]), Float.parseFloat(split[2])); - } else if (split.length == 1) { - return new Vector3f(Float.parseFloat(split[0])); + if (o instanceof List list && list.size() == 3) { + return new Vector3f(Float.parseFloat(list.get(0).toString()), Float.parseFloat(list.get(1).toString()), Float.parseFloat(list.get(2).toString())); } else { - throw new LocalizedResourceConfigException("warning.config.type.vector3f", stringFormat, option); + String stringFormat = o.toString(); + String[] split = stringFormat.split(","); + if (split.length == 3) { + return new Vector3f(Float.parseFloat(split[0]), Float.parseFloat(split[1]), Float.parseFloat(split[2])); + } else if (split.length == 1) { + return new Vector3f(Float.parseFloat(split[0])); + } else { + throw new LocalizedResourceConfigException("warning.config.type.vector3f", stringFormat, option); + } } } public static Quaternionf getAsQuaternionf(Object o, String option) { if (o == null) return new Quaternionf(); - String stringFormat = o.toString(); - String[] split = stringFormat.split(","); - if (split.length == 4) { - return new Quaternionf(Float.parseFloat(split[0]), Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3])); - } else if (split.length == 1) { - return QuaternionUtils.toQuaternionf(0, Math.toRadians(Float.parseFloat(split[0])), 0); + if (o instanceof List list && list.size() == 4) { + return new Quaternionf(Float.parseFloat(list.get(0).toString()), Float.parseFloat(list.get(1).toString()), Float.parseFloat(list.get(2).toString()), Float.parseFloat(list.get(3).toString())); } else { - throw new LocalizedResourceConfigException("warning.config.type.quaternionf", stringFormat, option); + String stringFormat = o.toString(); + String[] split = stringFormat.split(","); + if (split.length == 4) { + return new Quaternionf(Float.parseFloat(split[0]), Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3])); + } else if (split.length == 1) { + return QuaternionUtils.toQuaternionf(0, Math.toRadians(Float.parseFloat(split[0])), 0); + } else { + throw new LocalizedResourceConfigException("warning.config.type.quaternionf", stringFormat, option); + } } } } diff --git a/gradle.properties b/gradle.properties index d4e994cdc..a13ad6688 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.53.4 +project_version=0.0.53.5 config_version=32 lang_version=12 project_group=net.momirealms From 84a8fd8692489ce7e955ddfa5ce8ac1ba097b0cd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 04:05:58 +0800 Subject: [PATCH 33/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=8E=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=A8=A1=E5=9E=8B=E7=94=9F=E6=88=90=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/item/custom/topaz_trident_in_hand.json | 14 ++++++++++++++ .../models/item/custom/topaz_trident_throwing.json | 14 ++++++++++++++ .../craftengine/core/pack/AbstractPackManager.java | 2 ++ 3 files changed, 30 insertions(+) diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json index 52fbb8b40..a56ed9681 100644 --- a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_in_hand.json @@ -71,6 +71,7 @@ } } ], + "gui_light": "front", "display": { "thirdperson_righthand": { "rotation": [0, 60, 0], @@ -89,6 +90,19 @@ "firstperson_lefthand": { "rotation": [0, 90, -25], "translation": [-2.5, 7.5, 4.75] + }, + "ground": { + "rotation": [0, 0, 45], + "translation": [-2, 2, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [0, 0, -45], + "translation": [5, 5, 0], + "scale": [1.25, 1.25, 1.25] + }, + "fixed": { + "translation": [0, 6, 0] } } } \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json index fded0b6dc..90b814746 100644 --- a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/topaz_trident_throwing.json @@ -71,6 +71,7 @@ } } ], + "gui_light": "front", "display": { "thirdperson_righthand": { "rotation": [0, 90, 180], @@ -91,6 +92,19 @@ "rotation": [0, 90, -25], "translation": [0.75, -5, -0.75], "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "rotation": [0, 0, 45], + "translation": [-2, 2, 0], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [0, 0, -45], + "translation": [5, 5, 0], + "scale": [1.25, 1.25, 1.25] + }, + "fixed": { + "translation": [0, 6, 0] } } } \ No newline at end of file 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 df19992c8..34ead8527 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 @@ -1085,6 +1085,8 @@ public abstract class AbstractPackManager implements PackManager { if (originalItemModel == null) { plugin.logger().warn("Failed to load item model for [" + key + "] (legacy)"); continue; + } else { + originalItemModel = originalItemModel.deepCopy(); } JsonArray overrides; if (originalItemModel.has("overrides")) { From 31e4172140bc86b370a173c1fc145808a99b10de Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 04:36:47 +0800 Subject: [PATCH 34/73] =?UTF-8?q?=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/projectile/BukkitProjectileManager.java | 2 -- .../network/handler/ProjectilePacketHandler.java | 14 ++++++++++++-- .../craftengine/core/util/MiscUtils.java | 1 - gradle.properties | 2 +- 4 files changed, 13 insertions(+), 6 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 3f83a18e3..164055f18 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 @@ -13,7 +13,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; -import org.bukkit.Particle; import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.Projectile; @@ -29,7 +28,6 @@ import org.bukkit.inventory.ItemStack; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; public class BukkitProjectileManager implements Listener, ProjectileManager { private static BukkitProjectileManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 23358d9e5..0243f8184 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -55,10 +55,9 @@ public class ProjectilePacketHandler implements EntityPacketHandler { @Override public void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet); - Object converted = convertCustomProjectileMovePacket(packet, entityId); event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of( this.cachedPacket, - converted + convertCustomProjectileMovePacket(packet, entityId) ))); } @@ -127,4 +126,15 @@ public class ProjectilePacketHandler implements EntityPacketHandler { onGround ); } + + private Object convertCustomProjectileTeleportPacket(Object packet, int entityId) { + float xRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xRot(packet)); + float yRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$yRot(packet)); + boolean onGround = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$onGround(packet); + return FastNMS.INSTANCE.constructor$ClientboundTeleportEntityPacket( + entityId, this.projectile.projectile().x(), this.projectile.projectile().y(), this.projectile.projectile().z(), + MCUtils.packDegrees(-yRot), MCUtils.packDegrees(MCUtils.clamp(-xRot, -90.0F, 90.0F)), + onGround + ); + } } 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 b16bd6df5..3e9c4ba60 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 @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.util; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import org.joml.Quaternionf; import org.joml.Vector3f; -import software.amazon.awssdk.services.s3.endpoints.internal.Value; import java.util.ArrayList; import java.util.List; diff --git a/gradle.properties b/gradle.properties index a13ad6688..af4fa0f0e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.18 +nms_helper_version=0.65.19 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 0ebeef9481a08a1cd774f34c095c98729b08a051 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 11 May 2025 06:01:15 +0800 Subject: [PATCH 35/73] =?UTF-8?q?fix(network):=20=E8=A7=A3=E5=86=B3set?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E5=8C=85=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 1 + 1 file changed, 1 insertion(+) 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 dd0c37492..a4847d28d 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 @@ -1998,6 +1998,7 @@ public class PacketConsumers { EntityPacketHandler handler = user.entityPacketHandlers().get(id); if (handler != null) { handler.handleSetEntityData(user, event); + return; } if (Config.interceptEntityName()) { boolean isChanged = false; From f0340f3707706c75c301a2e68e498b452c2888a5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 11 May 2025 09:15:27 +0800 Subject: [PATCH 36/73] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E6=A0=87=E7=AD=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 35 ++++---- .../craftengine/bukkit/util/BlockTags.java | 83 +++++++++++++++++++ gradle.properties | 2 +- 3 files changed, 104 insertions(+), 16 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index e31773b82..98db57b67 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.BlockTags; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; @@ -13,47 +14,51 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.data.BlockPredicate; +import org.incendo.cloud.bukkit.parser.BlockPredicateParser; import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.BooleanParser; import org.incendo.cloud.parser.standard.ByteParser; import org.incendo.cloud.parser.standard.StringParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; -import java.util.Optional; +import java.util.*; import java.util.concurrent.CompletableFuture; public class TestCommand extends BukkitCommandFeature { + public static final Collection TARGET_BLOCK_SUGGESTIONS = new HashSet<>(); + + static { + for (Material material : Material.values()) { + TARGET_BLOCK_SUGGESTIONS.add(Suggestion.suggestion(material.getKey().toString())); + } + } public TestCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { super(commandManager, plugin); } @Override - @SuppressWarnings("deprecation") public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + .required("reset", BooleanParser.booleanParser()) + .required("setTag", NamespacedKeyParser.namespacedKeyParser()) + .required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS); } })) - .required("displayType", ByteParser.byteParser((byte) 0, (byte) 8)) - .required("translation", StringParser.stringParser()) - .required("rotation", StringParser.stringParser()) .handler(context -> { Player player = context.sender(); - NamespacedKey namespacedKey = context.get("id"); - ItemStack item = new ItemStack(Material.TRIDENT); - item.editMeta((meta) -> { - Item ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null); - Optional customModelData = ceItem.customModelData(); - customModelData.ifPresent(meta::setCustomModelData); - }); - player.getInventory().addItem(item); + player.sendMessage("开始测试"); + NamespacedKey key = context.get("setTag"); + BlockTags.test(plugin().adapt(player), context.get("reset"), context.get("targetBlock"), key.asString()); + player.sendMessage("结束测试"); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java index e7f746d29..ef7eb4cd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java @@ -1,9 +1,16 @@ package net.momirealms.craftengine.bukkit.util; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.Key; import java.util.HashMap; import java.util.Map; +import java.util.Optional; public class BlockTags { private static final Map CACHE = new HashMap<>(); @@ -24,4 +31,80 @@ public class BlockTags { return value; } } + + /** + * 用于测试下面的 buildFakeUpdateTagsPacket 方法 + * + * @param player CraftEngine玩家对象 + * @param reset 是否重置标签 + * @param targetBlock 测试添加标签的目标方块 + * @param setTag 测试添加的标签 + */ + public static void test(Player player, boolean reset, String targetBlock, String setTag) { + Map> addTags = new HashMap<>(); + if (!reset) { + Object registries = Reflections.instance$BuiltInRegistries$BLOCK; + Object key = FastNMS.INSTANCE.method$Registry$key(registries); + Map blockTags = new HashMap<>(); + IntList blockId = new IntArrayList(); + Object blockKey = KeyUtils.toResourceLocation(Key.of(targetBlock)); + Object block = FastNMS.INSTANCE.method$Registry$get(registries, blockKey); + Optional optionalBlockId = FastNMS.INSTANCE.method$BuiltInRegistries$getId(registries, block); + optionalBlockId.ifPresent(integer -> blockId.add(integer.intValue())); + blockTags.put(setTag, blockId); + addTags.put(key, blockTags); + } + Object packet = buildFakeUpdateTagsPacket(addTags); + player.sendPacket(packet, true); + } + + /** + * 构建模拟标签更新数据包(用于向客户端添加虚拟标签) + * + * @param addTags 需要添加的标签数据,结构为嵌套映射: + *
{@code
+     *               Map结构示例:
+     *               {
+     *                 注册表键1 (如BuiltInRegistries.ITEM.key) -> {
+     *                   "命名空间:值1" -> IntList.of(1, 2, 3),  // 该命名空间下生效的物品ID列表
+     *                   "命名空间:值2" -> IntList.of(5, 7)
+     *                 },
+     *                 注册表键2 (如BuiltInRegistries.BLOCK.key) -> {
+     *                   "minecraft:beacon_base_blocks" -> IntList.of(1024, 2048)
+     *                 },
+     *                 ....
+     *               }
+     *               }
+ * 其中:
+ * - 外层键:注册表对象(如物品/方块注册表)
+ * - 中间层键:标签的命名空间:值(字符串)
+ * - 值:包含注册表内项目数字ID的IntList + * + * @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象 + */ + @SuppressWarnings("unchecked") + public static Object buildFakeUpdateTagsPacket(Map> addTags) { + Map registriesNetworkPayload = (Map) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork(); + for (Map.Entry> entry : addTags.entrySet()) { + Object registryKey = entry.getKey(); + Map tagsToAdd = entry.getValue(); + Object existingPayload = registriesNetworkPayload.get(registryKey); + if (existingPayload == null) continue; + FriendlyByteBuf deserializeBuf = new FriendlyByteBuf(Unpooled.buffer()); + FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(existingPayload, deserializeBuf); + Map combinedTags = deserializeBuf.readMap( + FriendlyByteBuf::readUtf, + FriendlyByteBuf::readIntIdList + ); + combinedTags.putAll(tagsToAdd); + FriendlyByteBuf serializeBuf = new FriendlyByteBuf(Unpooled.buffer()); + serializeBuf.writeMap(combinedTags, + FriendlyByteBuf::writeUtf, + FriendlyByteBuf::writeIntIdList + ); + Object mergedPayload = FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$read(serializeBuf); + registriesNetworkPayload.put(registryKey, mergedPayload); + } + return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(registriesNetworkPayload); + } } diff --git a/gradle.properties b/gradle.properties index af4fa0f0e..22e20eb06 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.19 +nms_helper_version=0.65.20 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From e253c31e930eb2e416ef74964a6e3fc3d596896f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 15:44:33 +0800 Subject: [PATCH 37/73] =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=9F=93=E8=89=B2?= =?UTF-8?q?=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/RecipeEventListener.java | 145 +++++++++++------- .../craftengine/bukkit/util/Reflections.java | 7 + .../craftengine/core/item/ItemSettings.java | 15 ++ 3 files changed, 109 insertions(+), 58 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 aaa910a99..8fa4cdf02 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 @@ -330,14 +330,12 @@ public class RecipeEventListener implements Listener { if (clicked == null) return; Material type = clicked.getType(); if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return; - if (!VersionHelper.isOrAbove1_21_2()) { - if (clicked.getState() instanceof Campfire campfire) { - try { - Object blockEntity = Reflections.field$CraftBlockEntityState$tileEntity.get(campfire); - BukkitInjector.injectCookingBlockEntity(blockEntity); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject cooking block entity", e); - } + if (clicked.getState() instanceof Campfire campfire) { + try { + Object blockEntity = Reflections.field$CraftBlockEntityState$tileEntity.get(campfire); + BukkitInjector.injectCookingBlockEntity(blockEntity); + } catch (Exception e) { + this.plugin.logger().warn("Failed to inject cooking block entity", e); } } @@ -704,59 +702,90 @@ public class RecipeEventListener implements Listener { try { Object mcRecipe = Reflections.field$CraftComplexRecipe$recipe.get(complexRecipe); - if (!Reflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) { + + // Repair recipe + if (Reflections.clazz$RepairItemRecipe.isInstance(mcRecipe)) { + // repair item + ItemStack[] itemStacks = inventory.getMatrix(); + Pair onlyTwoItems = getTheOnlyTwoItem(itemStacks); + if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) { + inventory.setResult(null); + return; + } + + Item left = plugin.itemManager().wrap(onlyTwoItems.left()); + Item right = plugin.itemManager().wrap(onlyTwoItems.right()); + if (!left.id().equals(right.id())) { + inventory.setResult(null); + return; + } + + int totalDamage = right.damage().orElse(0) + left.damage().orElse(0); + int totalMaxDamage = left.maxDamage().get() + right.maxDamage().get(); + // should be impossible, but take care + if (totalDamage >= totalMaxDamage) { + inventory.setResult(null); + return; + } + + Player player; + try { + player = (Player) Reflections.method$InventoryView$getPlayer.invoke(event.getView()); + } catch (ReflectiveOperationException e) { + plugin.logger().warn("Failed to get inventory viewer", e); + return; + } + + Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); + if (customItemOptional.isEmpty()) { + inventory.setResult(null); + return; + } + + CustomItem customItem = customItemOptional.get(); + if (!customItem.settings().canRepair()) { + inventory.setResult(null); + return; + } + + Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player))); + int remainingDurability = totalMaxDamage - totalDamage; + int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); + newItem.damage(newItemDamage); + inventory.setResult(newItem.load()); + } else if (Reflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { + ItemStack[] itemStacks = inventory.getMatrix(); + Pair onlyTwoItems = getTheOnlyTwoItem(itemStacks); + if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) { + inventory.setResult(null); + return; + } + + Item left = plugin.itemManager().wrap(onlyTwoItems.left()); + Item right = plugin.itemManager().wrap(onlyTwoItems.right()); + // can't be two custom items + if (left.isCustomItem() && right.isCustomItem()) { + inventory.setResult(null); + return; + } + + Optional> customLeftItem = left.getCustomItem(); + if (customLeftItem.isPresent()) { + if (!customLeftItem.get().settings().dyeable()) { + inventory.setResult(null); + } + } else { + Optional> customRightItem = right.getCustomItem(); + if (customRightItem.isPresent()) { + if (!customRightItem.get().settings().dyeable()) { + inventory.setResult(null); + } + } + } + } else { inventory.setResult(null); return; } - - // repair item - ItemStack[] itemStacks = inventory.getMatrix(); - Pair onlyTwoItems = getTheOnlyTwoItem(itemStacks); - if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) { - inventory.setResult(null); - return; - } - - Item left = plugin.itemManager().wrap(onlyTwoItems.left()); - Item right = plugin.itemManager().wrap(onlyTwoItems.right()); - if (!left.id().equals(right.id())) { - inventory.setResult(null); - return; - } - - int totalDamage = right.damage().orElse(0) + left.damage().orElse(0); - int totalMaxDamage = left.maxDamage().get() + right.maxDamage().get(); - // should be impossible, but take care - if (totalDamage >= totalMaxDamage) { - inventory.setResult(null); - return; - } - - Player player; - try { - player = (Player) Reflections.method$InventoryView$getPlayer.invoke(event.getView()); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get inventory viewer", e); - return; - } - - Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); - if (customItemOptional.isEmpty()) { - inventory.setResult(null); - return; - } - - CustomItem customItem = customItemOptional.get(); - if (!customItem.settings().canRepair()) { - inventory.setResult(null); - return; - } - - Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player))); - int remainingDurability = totalMaxDamage - totalDamage; - int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); - newItem.damage(newItemDamage); - inventory.setResult(newItem.load()); } catch (Exception e) { this.plugin.logger().warn("Failed to handle minecraft custom recipe", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 64f6096c4..b12714cee 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5269,6 +5269,13 @@ public class Reflections { ) ); + public static final Class clazz$ArmorDyeRecipe = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.crafting.RecipeArmorDye", + "world.item.crafting.ArmorDyeRecipe" + ) + ); + public static final Field field$CraftComplexRecipe$recipe = requireNonNull( ReflectionUtils.getDeclaredField( clazz$CraftComplexRecipe, clazz$CustomRecipe, 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 c536b3725..b16dcf2a0 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 @@ -27,6 +27,7 @@ public class ItemSettings { boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; ProjectileMeta projectileMeta; + boolean dyeable = false; private ItemSettings() {} @@ -56,6 +57,7 @@ public class ItemSettings { newSettings.renameable = settings.renameable; newSettings.canPlaceRelatedVanillaBlock = settings.canPlaceRelatedVanillaBlock; newSettings.projectileMeta = settings.projectileMeta; + newSettings.dyeable = settings.dyeable; return newSettings; } @@ -95,6 +97,10 @@ public class ItemSettings { return tags; } + public boolean dyeable() { + return dyeable; + } + public List repairItems() { return anvilRepairItems; } @@ -144,6 +150,11 @@ public class ItemSettings { return this; } + public ItemSettings dyeable(boolean bool) { + this.dyeable = bool; + return this; + } + @FunctionalInterface public interface Modifier { @@ -217,6 +228,10 @@ public class ItemSettings { Quaternionf rotation = MiscUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation-left", "rotation"), "rotation-left"); return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation)); })); + registerFactory("dyeable", (value -> { + boolean bool = (boolean) value; + return settings -> settings.dyeable(bool); + })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { From b58d5d944cf0a827382909b3a31b76cd9522a3ca Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 15:55:20 +0800 Subject: [PATCH 38/73] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=9F=93=E8=89=B2?= =?UTF-8?q?=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/RecipeEventListener.java | 30 ++++--------------- .../craftengine/core/item/ItemSettings.java | 2 +- 2 files changed, 7 insertions(+), 25 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 8fa4cdf02..469cb7e1e 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 @@ -755,31 +755,13 @@ public class RecipeEventListener implements Listener { inventory.setResult(newItem.load()); } else if (Reflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { ItemStack[] itemStacks = inventory.getMatrix(); - Pair onlyTwoItems = getTheOnlyTwoItem(itemStacks); - if (onlyTwoItems.left() == null || onlyTwoItems.right() == null) { - inventory.setResult(null); - return; - } - - Item left = plugin.itemManager().wrap(onlyTwoItems.left()); - Item right = plugin.itemManager().wrap(onlyTwoItems.right()); - // can't be two custom items - if (left.isCustomItem() && right.isCustomItem()) { - inventory.setResult(null); - return; - } - - Optional> customLeftItem = left.getCustomItem(); - if (customLeftItem.isPresent()) { - if (!customLeftItem.get().settings().dyeable()) { + for (ItemStack itemStack : itemStacks) { + if (itemStack == null) continue; + Item item = plugin.itemManager().wrap(itemStack); + Optional> optionalCustomItem = item.getCustomItem(); + if (optionalCustomItem.isPresent() && !optionalCustomItem.get().settings().dyeable()) { inventory.setResult(null); - } - } else { - Optional> customRightItem = right.getCustomItem(); - if (customRightItem.isPresent()) { - if (!customRightItem.get().settings().dyeable()) { - inventory.setResult(null); - } + return; } } } else { 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 b16dcf2a0..bc8f9960f 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 @@ -27,7 +27,7 @@ public class ItemSettings { boolean renameable = true; boolean canPlaceRelatedVanillaBlock = false; ProjectileMeta projectileMeta; - boolean dyeable = false; + boolean dyeable = true; private ItemSettings() {} From 2d8eb48d5160d449d96b7e3a444b4af35d08c8b1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 17:28:11 +0800 Subject: [PATCH 39/73] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/furniture.yml | 6 +- .../default/configuration/templates.yml | 12 +++ .../bukkit/api/CraftEngineFurniture.java | 26 +++--- .../furniture/BukkitFurnitureManager.java | 80 ++++++++++------- .../entity/furniture/LoadedFurniture.java | 11 ++- .../bukkit/item/BukkitItemManager.java | 6 ++ .../bukkit/item/ComponentItemWrapper.java | 2 +- .../bukkit/item/ComponentTypes.java | 1 + .../item/behavior/FurnitureItemBehavior.java | 12 ++- .../item/factory/BukkitItemFactory.java | 6 ++ .../factory/ComponentItemFactory1_20_5.java | 20 +++++ .../item/factory/UniversalItemFactory.java | 15 ++++ .../feature/DebugSpawnFurnitureCommand.java | 3 +- .../plugin/command/feature/TestCommand.java | 10 +-- .../bukkit/util/LocationUtils.java | 6 ++ .../core/entity/furniture/Furniture.java | 2 + .../entity/furniture/FurnitureExtraData.java | 86 +++++++++++++++++++ .../entity/furniture/FurnitureManager.java | 5 +- .../craftengine/core/item/AbstractItem.java | 16 ++++ .../craftengine/core/item/ComponentKeys.java | 1 + .../craftengine/core/item/Item.java | 6 ++ .../craftengine/core/item/ItemFactory.java | 7 ++ .../craftengine/core/item/ItemManager.java | 2 + .../FurnitureItemLootEntryContainer.java | 58 +++++++++++++ .../core/loot/entry/LootEntryContainers.java | 2 + .../context/parameter/CommonParameters.java | 2 + .../craftengine/core/world/WorldPosition.java | 19 ++++ gradle.properties | 2 +- 28 files changed, 360 insertions(+), 64 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml b/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml index e8eb30a91..2816c5458 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/furniture.yml @@ -41,7 +41,7 @@ items: - 0,0,-0.1 0 - 1,0,-0.1 0 loot: - template: "default:loot_table/basic" + template: "default:loot_table/furniture" arguments: item: default:bench default:table_lamp: @@ -92,7 +92,7 @@ items: height: 0.4 interactive: true loot: - template: "default:loot_table/basic" + template: "default:loot_table/furniture" arguments: item: default:table_lamp default:wooden_chair: @@ -132,6 +132,6 @@ items: seats: - 0,0,-0.1 0 loot: - template: "default:loot_table/basic" + template: "default:loot_table/furniture" arguments: item: default:wooden_chair \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml index b2f321624..a281f7e41 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -968,6 +968,18 @@ templates#loot_tables: - type: item item: "{item}" + # drop the original furniture item or a fallback item + + # template: default:loot_table/furniture + # arguments: + # item: the fallback item + default:loot_table/furniture: + pools: + - rolls: 1 + entries: + - type: furniture_item + item: "{item}" + # drop with silk touch # template: default:loot_table/silk_touch diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index d611eec59..51fb36cd4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; @@ -41,7 +42,7 @@ public final class CraftEngineFurniture { } /** - * Places furniture at the certain location + * Places furniture at certain location * * @param location location * @param furnitureId furniture to place @@ -55,7 +56,7 @@ public final class CraftEngineFurniture { } /** - * Places furniture at the certain location + * Places furniture at certain location * * @param location location * @param furnitureId furniture to place @@ -66,11 +67,11 @@ public final class CraftEngineFurniture { public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; - return BukkitFurnitureManager.instance().place(furniture, location, anchorType, true); + return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); } /** - * Places furniture at the certain location + * Places furniture at certain location * * @param location location * @param furniture furniture to place @@ -79,11 +80,11 @@ public final class CraftEngineFurniture { */ @NotNull public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { - return BukkitFurnitureManager.instance().place(furniture, location, anchorType, true); + return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); } /** - * Places furniture at the certain location + * Places furniture at certain location * * @param location location * @param furnitureId furniture to place @@ -95,11 +96,11 @@ public final class CraftEngineFurniture { public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; - return BukkitFurnitureManager.instance().place(furniture, location, anchorType, playSound); + return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); } /** - * Places furniture at the certain location + * Places furniture at certain location * * @param location location * @param furniture furniture to place @@ -109,7 +110,7 @@ public final class CraftEngineFurniture { */ @NotNull public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { - return BukkitFurnitureManager.instance().place(furniture, location, anchorType, playSound); + return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); } /** @@ -222,7 +223,7 @@ public final class CraftEngineFurniture { } /** - * Removes furniture by providing a plugin furniture instance + * Removes furniture by providing furniture instance * * @param loadedFurniture loaded furniture * @param dropLoot whether to drop loots @@ -235,7 +236,7 @@ public final class CraftEngineFurniture { } /** - * Removes furniture by providing a plugin furniture instance + * Removes furniture by providing furniture instance * * @param loadedFurniture loaded furniture * @param player the player who removes the furniture @@ -251,7 +252,7 @@ public final class CraftEngineFurniture { } /** - * Removes furniture by providing a plugin furniture instance + * Removes furniture by providing furniture instance * * @param loadedFurniture loaded furniture * @param player the player who removes the furniture @@ -272,6 +273,7 @@ public final class CraftEngineFurniture { ContextHolder.Builder builder = ContextHolder.builder(); builder.withParameter(CommonParameters.LOCATION, vec3d); builder.withParameter(CommonParameters.WORLD, world); + builder.withOptionalParameter(CommonParameters.FURNITURE_ITEM, loadedFurniture.extraData().item().orElse(null)); if (player != null) { builder.withParameter(CommonParameters.PLAYER, player); //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, player.getItemInHand(InteractionHand.MAIN_HAND)); 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 ca76fb096..e94f4eaef 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 @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; @@ -20,7 +21,7 @@ import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.entity.*; import org.bukkit.event.HandlerList; @@ -31,13 +32,16 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import javax.annotation.Nullable; +import java.io.IOException; import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class BukkitFurnitureManager extends AbstractFurnitureManager { public static final NamespacedKey FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_id")); - public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type")); + // DEPRECATED + // public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type")); + public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_extra_data")); public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_to_base_entity")); public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_vector")); public static final NamespacedKey FURNITURE_COLLISION = Objects.requireNonNull(NamespacedKey.fromString("craftengine:collision")); @@ -66,19 +70,23 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } @Override - public Furniture place(CustomFurniture furniture, Vec3d vec3d, net.momirealms.craftengine.core.world.World world, AnchorType anchorType, boolean playSound) { - return this.place(furniture, new Location((World) world.platformWorld(), vec3d.x(), vec3d.y(), vec3d.z()), anchorType, playSound); + public Furniture place(WorldPosition position, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { + return this.place(LocationUtils.toLocation(position), furniture, extraData, playSound); } - public LoadedFurniture place(CustomFurniture furniture, Location location, AnchorType anchorType, boolean playSound) { - if (furniture.isAllowedPlacement(anchorType)) { - anchorType = furniture.getAnyPlacement(); + public LoadedFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { + Optional optionalAnchorType = extraData.anchorType(); + if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) { + extraData.anchorType(furniture.getAnyPlacement()); } - AnchorType finalAnchorType = anchorType; Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> { ItemDisplay display = (ItemDisplay) entity; display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_KEY, PersistentDataType.STRING, furniture.id().toString()); - display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, finalAnchorType.name()); + try { + display.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, extraData.toBytes()); + } catch (IOException e) { + this.plugin.logger().warn("Failed to set furniture PDC for " + furniture.id().toString(), e); + } handleBaseEntityLoadEarly(display); }); if (playSound) { @@ -224,9 +232,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { handleCollisionEntityLoadOnEntitiesLoad(interaction); } else if (entity instanceof Boat boat) { handleCollisionEntityLoadOnEntitiesLoad(boat); - } else if (entity instanceof Shulker shulker) { - // TODO 移除这一行,预计过一个月 - handleCollisionEntityLoadOnEntitiesLoad(shulker); } } } @@ -301,7 +306,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { boolean preventChange = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); if (above1_20_1) { if (!preventChange) { - LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture)); + LoadedFurniture furniture = addNewFurniture(display, customFurniture); furniture.initializeColliders(); for (Player player : display.getTrackedPlayers()) { this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); @@ -309,7 +314,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } } } else { - LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture)); + LoadedFurniture furniture = addNewFurniture(display, customFurniture); for (Player player : display.getTrackedPlayers()) { this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player)); @@ -373,7 +378,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { CustomFurniture customFurniture = optionalFurniture.get(); LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); if (previous != null) return; - LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(display, customFurniture)); + LoadedFurniture furniture = addNewFurniture(display, customFurniture); furniture.initializeColliders(); // safely do it here } } @@ -394,24 +399,37 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { collisionEntity.remove(); } - private AnchorType getAnchorType(Entity baseEntity, CustomFurniture furniture) { - String anchorType = baseEntity.getPersistentDataContainer().get(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING); - if (anchorType != null) { - try { - AnchorType unverified = AnchorType.valueOf(anchorType); - if (furniture.isAllowedPlacement(unverified)) { - return unverified; - } - } catch (IllegalArgumentException ignored) { - } - } - AnchorType anchorTypeEnum = furniture.getAnyPlacement(); - baseEntity.getPersistentDataContainer().set(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, anchorTypeEnum.name()); - return anchorTypeEnum; + private FurnitureExtraData getFurnitureExtraData(Entity baseEntity) throws IOException { + byte[] extraData = baseEntity.getPersistentDataContainer().get(FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY); + if (extraData == null) return FurnitureExtraData.builder().build(); + return FurnitureExtraData.fromBytes(extraData); } - private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture, AnchorType anchorType) { - LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, anchorType); +// private AnchorType getAnchorType(Entity baseEntity, CustomFurniture furniture) { +// String anchorType = baseEntity.getPersistentDataContainer().get(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING); +// if (anchorType != null) { +// try { +// AnchorType unverified = AnchorType.valueOf(anchorType); +// if (furniture.isAllowedPlacement(unverified)) { +// return unverified; +// } +// } catch (IllegalArgumentException ignored) { +// } +// } +// AnchorType anchorTypeEnum = furniture.getAnyPlacement(); +// baseEntity.getPersistentDataContainer().set(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, anchorTypeEnum.name()); +// return anchorTypeEnum; +// } + + private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) { + FurnitureExtraData extraData; + try { + extraData = getFurnitureExtraData(display); + } catch (IOException e) { + extraData = FurnitureExtraData.builder().build(); + plugin.logger().warn("Furniture extra data could not be loaded", e); + } + LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, extraData); this.furnitureByRealEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture); for (int entityId : loadedFurniture.entityIds()) { this.furnitureByEntityId.put(entityId, loadedFurniture); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index ac8ba908a..21d79d9ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -31,6 +31,7 @@ public class LoadedFurniture implements Furniture { private final Key id; private final CustomFurniture furniture; private final AnchorType anchorType; + private final FurnitureExtraData extraData; // location private final Location location; // base entity @@ -54,10 +55,11 @@ public class LoadedFurniture implements Furniture { public LoadedFurniture(Entity baseEntity, CustomFurniture furniture, - AnchorType anchorType) { + FurnitureExtraData extraData) { this.id = furniture.id(); + this.extraData = extraData; this.baseEntityId = baseEntity.getEntityId(); - this.anchorType = anchorType; + this.anchorType = extraData.anchorType().orElse(furniture.getAnyPlacement()); this.location = baseEntity.getLocation(); this.baseEntity = new WeakReference<>(baseEntity); this.furniture = furniture; @@ -305,6 +307,11 @@ public class LoadedFurniture implements Furniture { spawnSeatEntityForPlayer((Player) player.platformPlayer(), seat); } + @Override + public FurnitureExtraData extraData() { + return this.extraData; + } + public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { Location location = this.calculateSeatLocation(seat); Entity seatEntity = seat.limitPlayerRotation() ? 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 fe46abf8e..6433d7fd0 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 @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.item; +import com.saicone.rtag.item.ItemTagStream; import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BoneMealItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; @@ -163,6 +164,11 @@ public class BukkitItemManager extends AbstractItemManager { HandlerList.unregisterAll(this.debugStickListener); } + @Override + public Item fromByteArray(byte[] bytes) { + return this.factory.wrap(ItemTagStream.INSTANCE.fromBytes(bytes)); + } + @Override public ConfigParser parser() { return this.itemParser; 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 75f692f57..7a6e7c0a3 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 @@ -71,7 +71,7 @@ public class ComponentItemWrapper implements ItemWrapper { @Override public ItemWrapper copyWithCount(int count) { - ItemStack copied = item.clone(); + ItemStack copied = this.item.clone(); copied.setAmount(count); return new ComponentItemWrapper(copied); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java index 904cac448..d755ab11b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java @@ -25,6 +25,7 @@ public class ComponentTypes { public static final Object REPAIR_COST = getComponentType(ComponentKeys.REPAIR_COST); public static final Object CUSTOM_DATA = getComponentType(ComponentKeys.CUSTOM_DATA); public static final Object PROFILE = getComponentType(ComponentKeys.PROFILE); + public static final Object DYED_COLOR = getComponentType(ComponentKeys.DYED_COLOR); private ComponentTypes() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index ff062ebec..d4d8c2b0b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.entity.furniture.HitBox; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; @@ -126,7 +127,15 @@ public class FurnitureItemBehavior extends ItemBehavior { return InteractionResult.FAIL; } - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().place(customFurniture, furnitureLocation.clone(), anchorType, false); + Item item = context.getItem(); + + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().place( + furnitureLocation.clone(), customFurniture, + FurnitureExtraData.builder() + .item(item.copyWithCount(1)) + .anchorType(anchorType) + .dyedColor(item.dyedColor().orElse(-1)) + .build(), false); FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, loadedFurniture, furnitureLocation, context.getHand()); if (EventUtils.fireAndCheckCancel(placeEvent)) { @@ -135,7 +144,6 @@ public class FurnitureItemBehavior extends ItemBehavior { } if (!player.isCreativeMode()) { - Item item = context.getItem(); item.count(item.count() - 1); item.load(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 853271e93..0dd515534 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonElement; +import com.saicone.rtag.item.ItemTagStream; import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.EquipmentData; @@ -46,6 +47,11 @@ public abstract class BukkitItemFactory> extend } } + @Override + protected byte[] toByteArray(W item) { + return ItemTagStream.INSTANCE.toBytes(item.getItem()); + } + @Override protected boolean isBlockItem(W item) { return item.getItem().getType().isBlock(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index f7b5e76ff..2cf775754 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -244,6 +244,26 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory dyedColor(ComponentItemWrapper item) { + if (!item.hasComponent(ComponentTypes.DYED_COLOR)) return Optional.empty(); + return Optional.ofNullable( + (Integer) ComponentType.encodeJava( + ComponentTypes.DYED_COLOR, + item.getComponent(ComponentTypes.DYED_COLOR) + ).orElse(null) + ); + } + + @Override + protected void dyedColor(ComponentItemWrapper item, Integer color) { + if (color == null) { + item.resetComponent(ComponentTypes.DYED_COLOR); + } else { + item.setJavaComponent(ComponentTypes.DYED_COLOR, color); + } + } + @Override protected Optional maxDamage(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.MAX_DAMAGE)) return Optional.of((int) item.getItem().getType().getMaxDurability()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index 3dd72fe51..dbf97a69d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -152,6 +152,21 @@ public class UniversalItemFactory extends BukkitItemFactory { item.set(damage, "Damage"); } + @Override + protected Optional dyedColor(LegacyItemWrapper item) { + if (!item.hasTag("display", "color")) return Optional.empty(); + return Optional.of(item.get("display", "color")); + } + + @Override + protected void dyedColor(LegacyItemWrapper item, Integer color) { + if (color == null) { + item.remove("display", "color"); + } else { + item.set(color, "display", "color"); + } + } + @Override protected Optional maxDamage(LegacyItemWrapper item) { return Optional.of((int) item.getItem().getType().getMaxDurability()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java index df390ccf2..70914aa49 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.KeyUtils; @@ -55,7 +56,7 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index 01c719118..1dbfa8d8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -3,13 +3,19 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Location; +import org.bukkit.World; import org.jetbrains.annotations.NotNull; public class LocationUtils { private LocationUtils() {} + public static Location toLocation(WorldPosition position) { + return new Location((World) position.world().platformWorld(), position.position().x(), position.position().y(), position.position().z()); + } + public static Vec3d toVec3d(Location loc) { return new Vec3d(loc.getX(), loc.getY(), loc.getZ()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java index 42998e48b..249a5872d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java @@ -46,4 +46,6 @@ public interface Furniture { boolean hasExternalModel(); void spawnSeatEntityForPlayer(Player player, Seat seat); + + FurnitureExtraData extraData(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java new file mode 100644 index 000000000..7da9d6c4e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java @@ -0,0 +1,86 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; + +import java.io.IOException; +import java.util.Optional; + +public class FurnitureExtraData { + public static final String ITEM = "item"; + public static final String DYED_COLOR = "dyed_color"; + public static final String ANCHOR_TYPE = "anchor_type"; + + private final CompoundTag data; + + public FurnitureExtraData(CompoundTag data) { + this.data = data; + } + + public Optional> item() { + byte[] data = this.data.getByteArray(ITEM); + if (data == null) return Optional.empty(); + return Optional.of(CraftEngine.instance().itemManager().fromByteArray(data)); + } + + public Optional dyedColor() { + if (this.data.containsKey(DYED_COLOR)) return Optional.of(this.data.getInt(DYED_COLOR)); + return Optional.empty(); + } + + public Optional anchorType() { + if (this.data.containsKey(ANCHOR_TYPE)) return Optional.of(AnchorType.byId(this.data.getInt(ANCHOR_TYPE))); + return Optional.empty(); + } + + public FurnitureExtraData anchorType(AnchorType type) { + this.data.putInt(ANCHOR_TYPE, type.getId()); + return this; + } + + public static Builder builder() { + return new Builder(); + } + + public static FurnitureExtraData fromBytes(final byte[] data) throws IOException { + return new FurnitureExtraData(NBT.fromBytes(data)); + } + + public static byte[] toBytes(final FurnitureExtraData data) throws IOException { + return NBT.toBytes(data.data); + } + + public byte[] toBytes() throws IOException { + return toBytes(this); + } + + public static class Builder { + private final CompoundTag data; + + public Builder() { + this.data = new CompoundTag(); + } + + public Builder item(Item item) { + this.data.putByteArray(ITEM, item.toByteArray()); + return this; + } + + public Builder dyedColor(int color) { + if (color < 0) return this; + this.data.putInt(DYED_COLOR, color); + return this; + } + + public Builder anchorType(AnchorType type) { + this.data.putInt(ANCHOR_TYPE, type.getId()); + return this; + } + + public FurnitureExtraData build() { + return new FurnitureExtraData(data); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 7dd60f33b..50d4787c1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -4,8 +4,7 @@ import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import org.incendo.cloud.suggestion.Suggestion; import javax.annotation.Nullable; @@ -21,7 +20,7 @@ public interface FurnitureManager extends Manageable { Collection cachedSuggestions(); - Furniture place(CustomFurniture furniture, Vec3d vec3d, World world, AnchorType anchorType, boolean playSound); + Furniture place(WorldPosition position, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound); Optional furnitureById(Key id); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index cd8991160..70fbf6d8f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -93,6 +93,17 @@ public class AbstractItem, I> implements Item { return this.factory.maxDamage(this.item); } + @Override + public Item dyedColor(Integer data) { + this.factory.dyedColor(this.item, data); + return this; + } + + @Override + public Optional dyedColor() { + return this.factory.dyedColor(this.item); + } + @SuppressWarnings("unchecked") @Override public Optional> getCustomItem() { @@ -358,4 +369,9 @@ public class AbstractItem, I> implements Item { public void merge(Item another) { this.factory.merge(this.item, (W) ((AbstractItem) another).item); } + + @Override + public byte[] toByteArray() { + return this.factory.toByteArray(this.item); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java index 30e2be9ce..597639121 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java @@ -22,4 +22,5 @@ public class ComponentKeys { public static final Key REPAIR_COST = Key.of("minecraft", "repair_cost"); public static final Key CUSTOM_DATA = Key.of("minecraft", "custom_data"); public static final Key PROFILE = Key.of("minecraft", "profile"); + public static final Key DYED_COLOR = Key.of("minecraft", "dyed_color"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 1d12dc775..50786ace9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -56,6 +56,10 @@ public interface Item { Optional maxDamage(); + Item dyedColor(Integer data); + + Optional dyedColor(); + Item customName(String displayName); Optional customName(); @@ -145,4 +149,6 @@ public interface Item { Item mergeCopy(Item another); void merge(Item another); + + byte[] toByteArray(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index c747a5131..eb3c9fada 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -83,6 +83,10 @@ public abstract class ItemFactory, I> { protected abstract void damage(W item, Integer damage); + protected abstract Optional dyedColor(W item); + + protected abstract void dyedColor(W item, Integer color); + protected abstract Optional maxDamage(W item); protected abstract void maxDamage(W item, Integer damage); @@ -138,4 +142,7 @@ public abstract class ItemFactory, I> { protected abstract void equippable(W item, EquipmentData data); protected abstract Optional equippable(W item); + + protected abstract byte[] toByteArray(W item); + } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index c02f1aa54..a5320e710 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -41,6 +41,8 @@ public interface ItemManager extends Manageable, ModelGenerator { Item wrap(T itemStack); + Item fromByteArray(byte[] bytes); + Collection items(); Key itemId(T itemStack); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java new file mode 100644 index 000000000..b16ed84f8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.loot.entry; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.function.LootFunction; +import net.momirealms.craftengine.core.loot.function.LootFunctions; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Consumer; + +public class FurnitureItemLootEntryContainer extends SingleItemLootEntryContainer { + public static final Factory FACTORY = new Factory<>(); + private final boolean hasFallback; + + protected FurnitureItemLootEntryContainer(@Nullable Key item, List> conditions, List> lootFunctions, int weight, int quality) { + super(item, conditions, lootFunctions, weight, quality); + this.hasFallback = item != null; + } + + @Override + public Key type() { + return LootEntryContainers.FURNITURE_ITEM; + } + + @SuppressWarnings("unchecked") + @Override + protected void createItem(Consumer> lootConsumer, LootContext context) { + Optional> optionalItem = context.getOptionalParameter(CommonParameters.FURNITURE_ITEM); + if (optionalItem.isPresent()) { + lootConsumer.accept((Item) optionalItem.get()); + } else if (this.hasFallback) { + super.createItem(lootConsumer, context); + } + } + + public static class Factory implements LootEntryContainerFactory { + @SuppressWarnings("unchecked") + @Override + public LootEntryContainer create(Map arguments) { + Key item = Optional.ofNullable(arguments.get("item")).map(String::valueOf).map(Key::of).orElse(null); + int weight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("weight", 1), "weight"); + int quality = ResourceConfigUtils.getAsInt(arguments.getOrDefault("quality", 0), "quality"); + List> conditions = Optional.ofNullable(arguments.get("conditions")) + .map(it -> LootConditions.fromMapList((List>) it)) + .orElse(Collections.emptyList()); + List> functions = Optional.ofNullable(arguments.get("functions")) + .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList((List>) it))) + .orElse(Collections.emptyList()); + return new FurnitureItemLootEntryContainer<>(item, conditions, functions, weight, quality); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java index 5d44629dc..2d27fb6f1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java @@ -16,12 +16,14 @@ import java.util.Map; public class LootEntryContainers { public static final Key ALTERNATIVES = Key.from("craftengine:alternatives"); public static final Key ITEM = Key.from("craftengine:item"); + public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); public static final Key EXP = Key.from("craftengine:exp"); static { register(ALTERNATIVES, AlternativesLootEntryContainer.FACTORY); register(ITEM, SingleItemLootEntryContainer.FACTORY); register(EXP, ExpLootEntryContainer.FACTORY); + register(FURNITURE_ITEM, FurnitureItemLootEntryContainer.FACTORY); } public static void register(Key key, LootEntryContainerFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java index e84c45315..615aa93bb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; @@ -13,6 +14,7 @@ public final class CommonParameters { public static final ContextKey LAST_RANDOM = ContextKey.of("last_random"); public static final ContextKey LOCATION = ContextKey.of("location"); public static final ContextKey WORLD = ContextKey.of("world"); + public static final ContextKey> FURNITURE_ITEM = ContextKey.of("furniture_item"); public static final ContextKey FALLING_BLOCK = ContextKey.of("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.of("explosion_radius"); public static final ContextKey PLAYER = ContextKey.of("player"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java new file mode 100644 index 000000000..b2dc01529 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.core.world; + +public class WorldPosition { + private final World world; + private final Position position; + + public WorldPosition(Position position, World world) { + this.position = position; + this.world = world; + } + + public Position position() { + return position; + } + + public World world() { + return world; + } +} diff --git a/gradle.properties b/gradle.properties index 22e20eb06..313e0850e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,7 +21,7 @@ asm_version=9.8 asm_commons_version=9.8 jar_relocator_version=1.7 adventure_bundle_version=4.21.0 -adventure_platform_version=4.3.4 +adventure_platform_version=4.4.0 cloud_core_version=2.0.0 cloud_services_version=2.0.0 cloud_brigadier_version=2.0.0-beta.10 From 1b8dabb9e900db674bc2c8c12bc7aace07d452a9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 11 May 2025 20:22:22 +0800 Subject: [PATCH 40/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9F=93=E8=89=B2?= =?UTF-8?q?=E5=AE=B6=E5=85=B7=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../furniture/BukkitFurnitureElement.java | 48 +++++++++++-------- .../furniture/BukkitFurnitureManager.java | 3 +- .../entity/furniture/LoadedFurniture.java | 7 ++- .../entity/furniture/hitbox/CustomHitBox.java | 6 +-- .../furniture/hitbox/HappyGhastHitBox.java | 4 +- .../furniture/hitbox/InteractionHitBox.java | 10 ++-- .../furniture/hitbox/ShulkerHitBox.java | 9 +++- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../bukkit/util/LocationUtils.java | 8 +--- .../furniture/AbstractFurnitureElement.java | 16 ++++++- .../entity/furniture/FurnitureElement.java | 8 +++- .../entity/furniture/FurnitureExtraData.java | 4 +- .../core/entity/furniture/HitBox.java | 4 +- .../craftengine/core/world/WorldPosition.java | 43 +++++++++++++++-- 14 files changed, 119 insertions(+), 53 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index 044034209..e2d2a29f8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -10,9 +10,10 @@ import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -22,7 +23,7 @@ import java.util.UUID; import java.util.function.Consumer; public class BukkitFurnitureElement extends AbstractFurnitureElement { - private List cachedValues; + private final List commonValues; public BukkitFurnitureElement(Key item, Billboard billboard, @@ -30,35 +31,40 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { Vector3f scale, Vector3f translation, Vector3f offset, - Quaternionf rotation) { - super(item, billboard, transform, scale, translation, offset, rotation); + Quaternionf rotation, + boolean applyDyedColor) { + super(item, billboard, transform, scale, translation, offset, rotation, applyDyedColor); + this.commonValues = new ArrayList<>(); + ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.commonValues); + ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.commonValues); + ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(billboard().id(), this.commonValues); + ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(translation(), this.commonValues); + ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(transform().id(), this.commonValues); } @Override - public void initPackets(int entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets) { + public void initPackets(int entityId, @NotNull WorldPosition position, @NotNull Quaternionf conjugated, Integer dyedColor, Consumer packets) { Vector3f offset = conjugated.transform(new Vector3f(position())); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + entityId, UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(), Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 )); - packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues())); + packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(dyedColor))); } - private synchronized List getCachedValues() { - if (this.cachedValues == null) { - this.cachedValues = new ArrayList<>(); - Item item = BukkitItemManager.instance().createWrappedItem(item(), null); - if (item == null) { - CraftEngine.instance().logger().warn("Failed to create furniture element for " + item() + " because item " + item() + " not found"); - item = BukkitItemManager.instance().wrap(new ItemStack(Material.STONE)); + private synchronized List getCachedValues(Integer color) { + List cachedValues = new ArrayList<>(this.commonValues); + Item item = BukkitItemManager.instance().createWrappedItem(item(), null); + if (item == null) { + CraftEngine.instance().debug(() -> "Failed to create furniture element because item " + item() + " not found"); + item = BukkitItemManager.instance().wrap(new ItemStack(Material.BARRIER)); + } else { + if (color != null) { + item.dyedColor(color); + item.load(); } - ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), this.cachedValues); - ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.cachedValues); - ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.cachedValues); - ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(billboard().id(), this.cachedValues); - ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(translation(), this.cachedValues); - ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(transform().id(), this.cachedValues); } - return this.cachedValues; + ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), cachedValues); + return cachedValues; } } 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 e94f4eaef..38329375e 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 @@ -151,7 +151,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { MiscUtils.getAsVector3f(element.getOrDefault("scale", "1"), "scale"), MiscUtils.getAsVector3f(element.getOrDefault("translation", "0"), "translation"), MiscUtils.getAsVector3f(element.getOrDefault("position", "0"), "position"), - MiscUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation") + MiscUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation"), + (boolean) element.getOrDefault("apply-dyed-color", true) ); elements.add(furnitureElement); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 21d79d9ab..e12c41a4c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.Location; import org.bukkit.attribute.Attribute; @@ -94,10 +95,12 @@ public class LoadedFurniture implements Furniture { List colliders = new ArrayList<>(); World world = world(); + WorldPosition position = new WorldPosition(world, x, y, z, yaw, 0); + Integer dyedColor = this.extraData.dyedColor().orElse(null); for (FurnitureElement element : placement.elements()) { int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); fakeEntityIds.add(entityId); - element.initPackets(entityId, world, x, y, z, yaw, conjugated, packet -> { + element.initPackets(entityId, position, conjugated, dyedColor, packet -> { packets.add(packet); if (this.minimized) minimizedPackets.add(packet); }); @@ -109,7 +112,7 @@ public class LoadedFurniture implements Furniture { mainEntityIds.add(entityId); this.hitBoxes.put(entityId, hitBox); } - hitBox.initPacketsAndColliders(ids, world, x, y, z, yaw, conjugated, (packet, canBeMinimized) -> { + hitBox.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> { packets.add(packet); if (this.minimized && !canBeMinimized) { minimizedPackets.add(packet); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java index 5a3e0780e..6d2fe233b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomHitBox.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.NamespacedKey; import org.bukkit.Registry; @@ -51,11 +51,11 @@ public class CustomHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + entityId[0], UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(), FastNMS.INSTANCE.toNMSEntityType(this.entityType), 0, Reflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java index dae5e7afe..1aeeb4966 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -33,7 +33,7 @@ public class HappyGhastHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java index e48713e89..587034e32 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -53,8 +53,12 @@ public class InteractionHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); + double x = position.x(); + double y = position.y(); + double z = position.z(); + float yaw = position.xRot(); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0 @@ -66,7 +70,7 @@ public class InteractionHitBox extends AbstractHitBox { if (blocksBuilding() || this.canBeHitByProjectile()) { AABB ceAABB = AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y); Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ); - collider.accept(new BukkitCollider(world.serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding())); + collider.accept(new BukkitCollider(position.world().serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding())); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index 56d8985a4..530cb80b1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -196,9 +197,13 @@ public class ShulkerHitBox extends AbstractHitBox { } @Override - public void initPacketsAndColliders(int[] entityIds, World world, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { + public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { + double x = position.x(); + double y = position.y(); + double z = position.z(); + float yaw = position.xRot(); double originalY = y + offset.y; double integerPart = Math.floor(originalY); double fractionalPart = originalY - integerPart; @@ -228,7 +233,7 @@ public class ShulkerHitBox extends AbstractHitBox { Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, this.scale); packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance)), false); } - this.spawner.accept(entityIds, world, x, y, z, yaw, offset, packets, collider, aabb); + this.spawner.accept(entityIds, position.world(), x, y, z, yaw, offset, packets, collider, aabb); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to construct shulker hitbox spawn packet", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index d4d8c2b0b..d31586809 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -134,7 +134,7 @@ public class FurnitureItemBehavior extends ItemBehavior { FurnitureExtraData.builder() .item(item.copyWithCount(1)) .anchorType(anchorType) - .dyedColor(item.dyedColor().orElse(-1)) + .dyedColor(item.dyedColor().orElse(null)) .build(), false); FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, loadedFurniture, furnitureLocation, context.getHand()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index 1dbfa8d8c..8e4fb070e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -13,7 +13,7 @@ public class LocationUtils { private LocationUtils() {} public static Location toLocation(WorldPosition position) { - return new Location((World) position.world().platformWorld(), position.position().x(), position.position().y(), position.position().z()); + return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.xRot(), position.yRot()); } public static Vec3d toVec3d(Location loc) { @@ -33,11 +33,7 @@ public class LocationUtils { } public static Object above(Object blockPos) throws ReflectiveOperationException { - return toBlockPos( - FastNMS.INSTANCE.field$Vec3i$x(blockPos), - FastNMS.INSTANCE.field$Vec3i$y(blockPos) + 1, - FastNMS.INSTANCE.field$Vec3i$z(blockPos) - ); + return toBlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) + 1, FastNMS.INSTANCE.field$Vec3i$z(blockPos)); } public static Object toBlockPos(int x, int y, int z) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java index b2f4151f7..18cc2fa80 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java @@ -14,8 +14,16 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { private final Vector3f translation; private final Vector3f offset; private final Quaternionf rotation; + private final boolean applyDyedColor; - public AbstractFurnitureElement(Key item, Billboard billboard, ItemDisplayContext transform, Vector3f scale, Vector3f translation, Vector3f offset, Quaternionf rotation) { + public AbstractFurnitureElement(Key item, + Billboard billboard, + ItemDisplayContext transform, + Vector3f scale, + Vector3f translation, + Vector3f offset, + Quaternionf rotation, + boolean applyDyedColor) { this.billboard = billboard; this.transform = transform; this.scale = scale; @@ -23,6 +31,12 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { this.item = item; this.rotation = rotation; this.offset = offset; + this.applyDyedColor = applyDyedColor; + } + + @Override + public boolean applyDyedColor() { + return applyDyedColor; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index 3ed6f1449..c730621e8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -3,7 +3,9 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -18,11 +20,13 @@ public interface FurnitureElement { ItemDisplayContext transform(); + boolean applyDyedColor(); + Vector3f scale(); Vector3f translation(); Vector3f position(); - void initPackets(int entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, Consumer packets); + void initPackets(int entityId, @NotNull WorldPosition position, @NotNull Quaternionf conjugated, @Nullable Integer dyedColor, Consumer packets); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java index 7da9d6c4e..9ed9dad3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java @@ -68,8 +68,8 @@ public class FurnitureExtraData { return this; } - public Builder dyedColor(int color) { - if (color < 0) return this; + public Builder dyedColor(Integer color) { + if (color == null) return this; this.data.putInt(DYED_COLOR, color); return this; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java index 28d4208c1..cd145a799 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBox.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -14,7 +14,7 @@ public interface HitBox { Key type(); - void initPacketsAndColliders(int[] entityId, World world, double x, double y, double z, float yaw, Quaternionf conjugated, + void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer packets, Consumer collider, BiConsumer aabb); void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer aabbs); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java index b2dc01529..f4024f04c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java @@ -2,18 +2,51 @@ package net.momirealms.craftengine.core.world; public class WorldPosition { private final World world; - private final Position position; + private final double x; + private final double y; + private final double z; + private final float xRot; + private final float yRot; - public WorldPosition(Position position, World world) { - this.position = position; + public WorldPosition(World world, Position position, float xRot, float yRot) { + this.x = position.x(); + this.y = position.y(); + this.z = position.z(); this.world = world; + this.xRot = xRot; + this.yRot = yRot; } - public Position position() { - return position; + public WorldPosition(World world, double x, double y, double z, float xRot, float yRot) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.xRot = xRot; + this.yRot = yRot; + } + + public double x() { + return x; + } + + public double y() { + return y; + } + + public double z() { + return z; } public World world() { return world; } + + public float xRot() { + return xRot; + } + + public float yRot() { + return yRot; + } } From fb1d3ed42f6e36d8a03e1689794536f56e80970a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 00:28:32 +0800 Subject: [PATCH 41/73] =?UTF-8?q?=E9=98=BB=E6=AD=A2=E4=BD=8E=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=B0=86=E8=87=AA=E5=AE=9A=E4=B9=89=E7=89=A9=E5=93=81?= =?UTF-8?q?=E6=94=BE=E5=88=B0=E9=A9=AC=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 7 ++ .../item/listener/ArmorEventListener.java | 102 ++++++++++++++++++ .../{ => listener}/DebugStickListener.java | 3 +- .../{ => listener}/ItemEventListener.java | 2 +- gradle.properties | 2 +- 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/{ => listener}/DebugStickListener.java (98%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/{ => listener}/ItemEventListener.java (99%) 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 6433d7fd0..89798dd29 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 @@ -6,6 +6,9 @@ import net.momirealms.craftengine.bukkit.item.behavior.BoneMealItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; +import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener; +import net.momirealms.craftengine.bukkit.item.listener.DebugStickListener; +import net.momirealms.craftengine.bukkit.item.listener.ItemEventListener; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.ItemUtils; @@ -63,6 +66,7 @@ public class BukkitItemManager extends AbstractItemManager { private final BukkitCraftEngine plugin; private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; + private final ArmorEventListener armorEventListener; private final ItemParser itemParser; public BukkitItemManager(BukkitCraftEngine plugin) { @@ -72,6 +76,7 @@ public class BukkitItemManager extends AbstractItemManager { this.factory = BukkitItemFactory.create(plugin); this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); + this.armorEventListener = new ArmorEventListener(); this.itemParser = new ItemParser(); this.registerAllVanillaItems(); if (plugin.hasMod()) { @@ -130,6 +135,7 @@ public class BukkitItemManager extends AbstractItemManager { public void delayedInit() { Bukkit.getPluginManager().registerEvents(this.itemEventListener, this.plugin.bootstrap()); Bukkit.getPluginManager().registerEvents(this.debugStickListener, this.plugin.bootstrap()); + Bukkit.getPluginManager().registerEvents(this.armorEventListener, this.plugin.bootstrap()); } public static BukkitItemManager instance() { @@ -162,6 +168,7 @@ public class BukkitItemManager extends AbstractItemManager { this.unload(); HandlerList.unregisterAll(this.itemEventListener); HandlerList.unregisterAll(this.debugStickListener); + HandlerList.unregisterAll(this.armorEventListener); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java new file mode 100644 index 000000000..0b748e981 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java @@ -0,0 +1,102 @@ +package net.momirealms.craftengine.bukkit.item.listener; + +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.Material; +import org.bukkit.entity.Horse; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.HorseInventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Map; + +public class ArmorEventListener implements Listener { + + // 只有在没有equippable组件的版本才生效,阻止自定义物品放到马上 + // 低版本没有自定义盔甲,所以完全不需要考虑能放置上去的情况 + @EventHandler(ignoreCancelled = true) + public void onInteractHorse(PlayerInteractEntityEvent event) { + if (VersionHelper.isOrAbove1_21_2()) return; + if (event.getRightClicked() instanceof Horse horse) { + ItemStack itemInHand = event.getPlayer().getInventory().getItem(event.getHand()); + if (horse.getInventory().getArmor() == null) { + switch (itemInHand.getType()) { + case LEATHER_HORSE_ARMOR, IRON_HORSE_ARMOR, GOLDEN_HORSE_ARMOR, DIAMOND_HORSE_ARMOR -> { + if (CraftEngineItems.isCustomItem(itemInHand)) { + event.setCancelled(true); + } + } + } + } else if (horse.getInventory().getSaddle() == null) { + if (itemInHand.getType() == Material.SADDLE) { + if (CraftEngineItems.isCustomItem(itemInHand)) { + event.setCancelled(true); + } + } + } + } + } + + // 处理低版本的马物品栏 + @EventHandler(ignoreCancelled = true) + public void onMoveItemInHorseInventory(InventoryClickEvent event) { + if (VersionHelper.isOrAbove1_21_2()) return; + if (!(event.getInventory() instanceof HorseInventory horseInventory)) { + return; + } + if (event.getClickedInventory() == event.getWhoClicked().getInventory()) { + ItemStack currentItem = event.getCurrentItem(); + if (event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) { + if (currentItem != null && CraftEngineItems.isCustomItem(currentItem)) { + event.setCancelled(true); + } + } + } else if (event.getClickedInventory() == horseInventory) { + ItemStack itemInCursor = event.getCursor(); + if (event.getAction() == InventoryAction.SWAP_WITH_CURSOR || event.getAction() == InventoryAction.PLACE_ALL || event.getAction() == InventoryAction.PLACE_ONE) { + if (!ItemUtils.isEmpty(itemInCursor) && CraftEngineItems.isCustomItem(itemInCursor)) { + event.setCancelled(true); + return; + } + } + if (event.getAction() == InventoryAction.HOTBAR_SWAP) { + int slot = event.getHotbarButton(); + if (slot != -1) { + ItemStack itemInHotBar = event.getWhoClicked().getInventory().getItem(slot); + if (!ItemUtils.isEmpty(itemInHotBar) && CraftEngineItems.isCustomItem(itemInHotBar)) { + event.setCancelled(true); + return; + } + } else { + ItemStack offHand = event.getWhoClicked().getInventory().getItemInOffHand(); + if (!ItemUtils.isEmpty(offHand) && CraftEngineItems.isCustomItem(offHand)) { + event.setCancelled(true); + return; + } + } + } + } + } + + @EventHandler(ignoreCancelled = true) + public void onMoveItemInHorseInventory(InventoryDragEvent event) { + if (VersionHelper.isOrAbove1_21_2()) return; + if (!(event.getInventory() instanceof HorseInventory horseInventory)) { + return; + } + for (Map.Entry item : event.getNewItems().entrySet()) { + if (item.getKey() == 0 || item.getKey() == 1) { + if (!ItemUtils.isEmpty(item.getValue()) && CraftEngineItems.isCustomItem(item.getValue())) { + event.setCancelled(true); + return; + } + } + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java similarity index 98% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/DebugStickListener.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index af5bbd4fd..ff87989ed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -1,8 +1,9 @@ -package net.momirealms.craftengine.bukkit.item; +package net.momirealms.craftengine.bukkit.item.listener; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java similarity index 99% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index bc5e9772f..18d04e54c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.item; +package net.momirealms.craftengine.bukkit.item.listener; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; diff --git a/gradle.properties b/gradle.properties index 313e0850e..7287d641c 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.53.5 +project_version=0.0.53.6 config_version=32 lang_version=12 project_group=net.momirealms From 4da834d3180b9654f2690532bce2bf9f237e6189 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 01:10:52 +0800 Subject: [PATCH 42/73] =?UTF-8?q?=E5=A2=9E=E5=BC=BAextra=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/LoadedFurniture.java | 18 +++++++++++++++++- .../core/entity/furniture/Furniture.java | 4 ++++ .../entity/furniture/FurnitureExtraData.java | 12 ++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index e12c41a4c..632b581bc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.*; @@ -32,7 +33,7 @@ public class LoadedFurniture implements Furniture { private final Key id; private final CustomFurniture furniture; private final AnchorType anchorType; - private final FurnitureExtraData extraData; + private FurnitureExtraData extraData; // location private final Location location; // base entity @@ -315,6 +316,21 @@ public class LoadedFurniture implements Furniture { return this.extraData; } + @Override + public void setExtraData(FurnitureExtraData extraData) { + this.extraData = extraData; + this.save(); + } + + @Override + public void save() { + try { + this.baseEntity().getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, this.extraData.toBytes()); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to save furniture data.", e); + } + } + public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { Location location = this.calculateSeatLocation(seat); Entity seatEntity = seat.limitPlayerRotation() ? diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java index 249a5872d..fea19d1e0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java @@ -48,4 +48,8 @@ public interface Furniture { void spawnSeatEntityForPlayer(Player player, Seat seat); FurnitureExtraData extraData(); + + void setExtraData(FurnitureExtraData extraData); + + void save(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java index 9ed9dad3d..940b0b0be 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java @@ -19,6 +19,18 @@ public class FurnitureExtraData { this.data = data; } + public static FurnitureExtraData of(CompoundTag data) { + return new FurnitureExtraData(data); + } + + public CompoundTag copyTag() { + return this.data.copy(); + } + + public CompoundTag unsafeTag() { + return this.data; + } + public Optional> item() { byte[] data = this.data.getByteArray(ITEM); if (data == null) return Optional.empty(); From 40adb5b93fcc794ec08f86fd216d5c64faccb071 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 01:12:52 +0800 Subject: [PATCH 43/73] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/entity/furniture/LoadedFurniture.java | 2 +- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 632b581bc..daaeddaf6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -331,7 +331,7 @@ public class LoadedFurniture implements Furniture { } } - public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { + private void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { Location location = this.calculateSeatLocation(seat); Entity seatEntity = seat.limitPlayerRotation() ? EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> { 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 a4847d28d..912bf704e 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 @@ -1740,7 +1740,7 @@ public class PacketConsumers { } else { furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { if (furniture.tryOccupySeat(seatPos)) { - furniture.spawnSeatEntityForPlayer(Objects.requireNonNull(player.getPlayer()), seatPos); + furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); } }); } From 609cdb65f8f33d231d1bf46622dc8cb861fccd3b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 03:01:46 +0800 Subject: [PATCH 44/73] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E4=BE=A7block=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/fix_client_visual.yml | 10 ++- .../bukkit/block/BlockEventListener.java | 9 ++ .../bukkit/block/BukkitBlockManager.java | 84 ++++++++++++++---- .../plugin/command/feature/TestCommand.java | 1 - .../plugin/network/PacketConsumers.java | 2 +- .../craftengine/bukkit/util/BlockTags.java | 83 ------------------ .../craftengine/bukkit/util/KeyUtils.java | 4 + .../craftengine/bukkit/util/TagUtils.java | 87 +++++++++++++++++++ .../momirealms/craftengine/core/util/Key.java | 4 + gradle.properties | 2 +- 10 files changed, 182 insertions(+), 104 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml index 795eae21a..8fc54c072 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml @@ -1,5 +1,5 @@ -# client-bound-data requires CraftEngine mod to apply items: + # client-bound-data requires CraftEngine mod to apply minecraft:string: client-bound-data: components: @@ -17,4 +17,10 @@ items: minecraft:block_state: instrument: "harp" powered: "false" - note: "0" \ No newline at end of file + note: "0" + +blocks: + minecraft:note_block: + settings: + client-bound-tags: + - minecraft:beacon_base_block \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index a31e0023a..e3b9f07cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -33,6 +33,7 @@ import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.ItemStack; @@ -49,6 +50,14 @@ public class BlockEventListener implements Listener { this.enableNoteBlockCheck = enableNoteBlockCheck; } + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Object packet = this.manager.cachedUpdateTagsPacket; + if (packet != null) { + this.plugin.networkManager().sendPacket(event.getPlayer(), packet); + } + } + @EventHandler(ignoreCancelled = true) public void onPlayerAttack(EntityDamageByEntityEvent event) { if (!VersionHelper.isOrAbove1_20_5()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index af14fc4d1..5e8d9a78a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -11,10 +11,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.bukkit.util.RegistryUtils; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; @@ -34,12 +31,15 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -49,6 +49,7 @@ import java.io.File; import java.lang.reflect.Field; import java.nio.file.Path; import java.util.*; +import java.util.stream.Collectors; public class BukkitBlockManager extends AbstractBlockManager { private static BukkitBlockManager instance; @@ -92,6 +93,10 @@ public class BukkitBlockManager extends AbstractBlockManager { private final BlockEventListener blockEventListener; private final FallingBlockRemoveListener fallingBlockRemoveListener; + private Map> clientBoundTags = Map.of(); + private Map> previousTags = Map.of(); + protected Object cachedUpdateTagsPacket; + public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin); this.plugin = plugin; @@ -146,6 +151,8 @@ public class BukkitBlockManager extends AbstractBlockManager { this.modBlockStates.clear(); if (EmptyBlock.STATE != null) Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.STATE); + this.previousTags = this.clientBoundTags; + this.clientBoundTags = new HashMap<>(); } @Override @@ -165,6 +172,26 @@ public class BukkitBlockManager extends AbstractBlockManager { initSuggestions(); resetPacketConsumers(); clearCache(); + resendTags(); + } + + private void resendTags() { + // if there's no change + if (this.clientBoundTags.equals(this.previousTags)) return; + List list = new ArrayList<>(); + for (Map.Entry> entry : this.clientBoundTags.entrySet()) { + list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue())); + } + Object packet = TagUtils.createUpdateTagsPacket(Map.of(Reflections.instance$Registries$BLOCK, list)); + for (Player player : Bukkit.getOnlinePlayers()) { + this.plugin.networkManager().sendPacket(player, packet); + } + // 如果空,那么新来的玩家就没必要收到更新包了 + if (list.isEmpty()) { + this.cachedUpdateTagsPacket = null; + } else { + this.cachedUpdateTagsPacket = packet; + } } private void clearCache() { @@ -333,10 +360,18 @@ public class BukkitBlockManager extends AbstractBlockManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { - // check duplicated config - if (byId.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.block.duplicate"); + if (id.namespace().equals("minecraft") && Registry.MATERIAL.get(KeyUtils.toNamespacedKey(id)) != null) { + parseVanillaBlock(pack, path, id, section); + } else { + // check duplicated config + if (byId.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.block.duplicate"); + } + parseCustomBlock(pack, path, id, section); } + } + + private void parseCustomBlock(Pack pack, Path path, Key id, Map section) { // read block settings BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); @@ -458,14 +493,14 @@ public class BukkitBlockManager extends AbstractBlockManager { Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) - .appearances(appearances) - .variantMapper(variants) - .lootTable(lootTable) - .properties(properties) - .settings(settings) - .behavior(behaviors) - .events(events) - .build(); + .appearances(appearances) + .variantMapper(variants) + .lootTable(lootTable) + .properties(properties) + .settings(settings) + .behavior(behaviors) + .events(events) + .build(); // bind appearance and real state for (ImmutableBlockState state : block.variantProvider().states()) { @@ -479,7 +514,7 @@ public class BukkitBlockManager extends AbstractBlockManager { appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new ArrayList<>()).add(state.customBlockState().registryId()); } - byId.put(id, block); + BukkitBlockManager.this.byId.put(id, block); // generate mod assets if (Config.generateModAssets()) { @@ -489,6 +524,23 @@ public class BukkitBlockManager extends AbstractBlockManager { } } } + + private void parseVanillaBlock(Pack pack, Path path, Key id, Map section) { + Map settings = MiscUtils.castToMap(section.get("settings"), true); + if (settings != null) { + Object clientBoundTags = settings.get("client-bound-tags"); + if (clientBoundTags instanceof List list) { + List clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList(); + try { + Object nmsBlock = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$BLOCK, KeyUtils.toResourceLocation(id)); + FastNMS.INSTANCE.method$IdMap$getId(Reflections.instance$BuiltInRegistries$BLOCK, nmsBlock).ifPresent(i -> + BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags)); + } catch (ReflectiveOperationException e) { + BukkitBlockManager.this.plugin.logger().warn("Unable to get block " + id, e); + } + } + } + } } private Map> parseProperties(Map propertiesSection) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 4692de9a3..69bcf57e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -51,7 +51,6 @@ public class TestCommand extends BukkitCommandFeature { Player player = context.sender(); player.sendMessage("开始测试"); NamespacedKey key = context.get("setTag"); - BlockTags.test(plugin().adapt(player), context.get("reset"), context.get("targetBlock"), key.asString()); player.sendMessage("结束测试"); }); } 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 912bf704e..c35ecd914 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 @@ -1790,7 +1790,7 @@ public class PacketConsumers { buf.writeLong(seed); } } else { - Optional optionalSound = FastNMS.INSTANCE.method$BuiltInRegistries$byId(Reflections.instance$BuiltInRegistries$SOUND_EVENT, id - 1); + Optional optionalSound = FastNMS.INSTANCE.method$IdMap$byId(Reflections.instance$BuiltInRegistries$SOUND_EVENT, id - 1); if (optionalSound.isEmpty()) return; Object soundEvent = optionalSound.get(); Key soundId = Key.of(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java index ef7eb4cd0..e7f746d29 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java @@ -1,16 +1,9 @@ package net.momirealms.craftengine.bukkit.util; -import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.Key; import java.util.HashMap; import java.util.Map; -import java.util.Optional; public class BlockTags { private static final Map CACHE = new HashMap<>(); @@ -31,80 +24,4 @@ public class BlockTags { return value; } } - - /** - * 用于测试下面的 buildFakeUpdateTagsPacket 方法 - * - * @param player CraftEngine玩家对象 - * @param reset 是否重置标签 - * @param targetBlock 测试添加标签的目标方块 - * @param setTag 测试添加的标签 - */ - public static void test(Player player, boolean reset, String targetBlock, String setTag) { - Map> addTags = new HashMap<>(); - if (!reset) { - Object registries = Reflections.instance$BuiltInRegistries$BLOCK; - Object key = FastNMS.INSTANCE.method$Registry$key(registries); - Map blockTags = new HashMap<>(); - IntList blockId = new IntArrayList(); - Object blockKey = KeyUtils.toResourceLocation(Key.of(targetBlock)); - Object block = FastNMS.INSTANCE.method$Registry$get(registries, blockKey); - Optional optionalBlockId = FastNMS.INSTANCE.method$BuiltInRegistries$getId(registries, block); - optionalBlockId.ifPresent(integer -> blockId.add(integer.intValue())); - blockTags.put(setTag, blockId); - addTags.put(key, blockTags); - } - Object packet = buildFakeUpdateTagsPacket(addTags); - player.sendPacket(packet, true); - } - - /** - * 构建模拟标签更新数据包(用于向客户端添加虚拟标签) - * - * @param addTags 需要添加的标签数据,结构为嵌套映射: - *
{@code
-     *               Map结构示例:
-     *               {
-     *                 注册表键1 (如BuiltInRegistries.ITEM.key) -> {
-     *                   "命名空间:值1" -> IntList.of(1, 2, 3),  // 该命名空间下生效的物品ID列表
-     *                   "命名空间:值2" -> IntList.of(5, 7)
-     *                 },
-     *                 注册表键2 (如BuiltInRegistries.BLOCK.key) -> {
-     *                   "minecraft:beacon_base_blocks" -> IntList.of(1024, 2048)
-     *                 },
-     *                 ....
-     *               }
-     *               }
- * 其中:
- * - 外层键:注册表对象(如物品/方块注册表)
- * - 中间层键:标签的命名空间:值(字符串)
- * - 值:包含注册表内项目数字ID的IntList - * - * @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象 - */ - @SuppressWarnings("unchecked") - public static Object buildFakeUpdateTagsPacket(Map> addTags) { - Map registriesNetworkPayload = (Map) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork(); - for (Map.Entry> entry : addTags.entrySet()) { - Object registryKey = entry.getKey(); - Map tagsToAdd = entry.getValue(); - Object existingPayload = registriesNetworkPayload.get(registryKey); - if (existingPayload == null) continue; - FriendlyByteBuf deserializeBuf = new FriendlyByteBuf(Unpooled.buffer()); - FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(existingPayload, deserializeBuf); - Map combinedTags = deserializeBuf.readMap( - FriendlyByteBuf::readUtf, - FriendlyByteBuf::readIntIdList - ); - combinedTags.putAll(tagsToAdd); - FriendlyByteBuf serializeBuf = new FriendlyByteBuf(Unpooled.buffer()); - serializeBuf.writeMap(combinedTags, - FriendlyByteBuf::writeUtf, - FriendlyByteBuf::writeIntIdList - ); - Object mergedPayload = FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$read(serializeBuf); - registriesNetworkPayload.put(registryKey, mergedPayload); - } - return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(registriesNetworkPayload); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java index 12d203b76..eabcb257d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java @@ -23,4 +23,8 @@ public class KeyUtils { public static Object toResourceLocation(Key key) { return toResourceLocation(key.namespace(), key.value()); } + + public static NamespacedKey toNamespacedKey(Key key) { + return new NamespacedKey(key.namespace(), key.value()); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java new file mode 100644 index 000000000..e54f30677 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java @@ -0,0 +1,87 @@ +package net.momirealms.craftengine.bukkit.util; + +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class TagUtils { + + private TagUtils() {} + + /** + * 构建模拟标签更新数据包(用于向客户端添加虚拟标签) + * + * @param tags 需要添加的标签数据,结构为嵌套映射: + *
{@code
+     *               Map结构示例:
+     *               {
+     *                 注册表键1 (如BuiltInRegistries.ITEM.key) -> {
+     *                   "命名空间:值1" -> IntList.of(1, 2, 3),  // 该命名空间下生效的物品ID列表
+     *                   "命名空间:值2" -> IntList.of(5, 7)
+     *                 },
+     *                 注册表键2 (如BuiltInRegistries.BLOCK.key) -> {
+     *                   "minecraft:beacon_base_blocks" -> IntList.of(1024, 2048)
+     *                 },
+     *                 ....
+     *               }
+     *               }
+ * 其中:
+ * - 外层键:注册表ResourceKey
+ * - 中间层键:标签的命名空间:值(字符串)
+ * - 值:包含注册表内项目数字ID的IntList + * + * @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象 + */ + @SuppressWarnings("unchecked") + public static Object createUpdateTagsPacket(Map> tags) { + Map registriesNetworkPayload = (Map) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork(); + Map modified = new HashMap<>(); + for (Map.Entry> entry : tags.entrySet()) { + Object existingPayload = registriesNetworkPayload.get(entry.getKey()); + if (existingPayload == null) continue; + FriendlyByteBuf deserializeBuf = new FriendlyByteBuf(Unpooled.buffer()); + FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(existingPayload, deserializeBuf); + Map originalTags = deserializeBuf.readMap( + FriendlyByteBuf::readUtf, + FriendlyByteBuf::readIntIdList + ); + Map> reversedTags = new HashMap<>(); + for (Map.Entry tagEntry : originalTags.entrySet()) { + for (int id : tagEntry.getValue()) { + reversedTags.computeIfAbsent(id, k -> new ArrayList<>()).add(tagEntry.getKey()); + } + } + for (TagEntry tagEntry : entry.getValue()) { + reversedTags.remove(tagEntry.id); + for (String tag : tagEntry.tags) { + reversedTags.computeIfAbsent(tagEntry.id, k -> new ArrayList<>()).add(tag); + } + } + Map processedTags = new HashMap<>(); + for (Map.Entry> tagEntry : reversedTags.entrySet()) { + for (String tag : tagEntry.getValue()) { + processedTags.computeIfAbsent(tag, k -> new IntArrayList()).addLast(tagEntry.getKey()); + } + } + FriendlyByteBuf serializeBuf = new FriendlyByteBuf(Unpooled.buffer()); + serializeBuf.writeMap(processedTags, + FriendlyByteBuf::writeUtf, + FriendlyByteBuf::writeIntIdList + ); + Object mergedPayload = FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$read(serializeBuf); + modified.put(entry.getKey(), mergedPayload); + } + return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(modified); + } + + public record TagEntry(int id, List tags) { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java index ed43ffe8c..994cf4b6c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java @@ -57,6 +57,10 @@ public record Key(String namespace, String value) { return namespace + ":" + value; } + public String asString() { + return namespace + ":" + value; + } + private static String[] decompose(String id, String namespace) { String[] strings = new String[]{namespace, id}; int i = id.indexOf(':'); diff --git a/gradle.properties b/gradle.properties index 7287d641c..ec72047d6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.20 +nms_helper_version=0.65.21 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 988d4981216fb4662a1306f35fe4ac21ff2e7269 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 03:03:18 +0800 Subject: [PATCH 45/73] Update fix_client_visual.yml --- .../resources/default/configuration/fix_client_visual.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml index 8fc54c072..f9d659368 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml @@ -23,4 +23,4 @@ blocks: minecraft:note_block: settings: client-bound-tags: - - minecraft:beacon_base_block \ No newline at end of file + - minecraft:beacon_base_blocks \ No newline at end of file From e9015345e0782a2e0636f85da3cf5a716aae5f04 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 12 May 2025 09:55:17 +0800 Subject: [PATCH 46/73] =?UTF-8?q?feat(client-mod):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A8=A1=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加取消方块更新功能 - 修复保存配置文件问题 - 修复网络通讯打包解包 --- .../plugin/network/PacketConsumers.java | 62 ++++++++++++------ .../craftengine/bukkit/util/Reflections.java | 16 +++++ .../client/CraftEngineFabricModClient.java | 27 ++++++++ .../fabric/client/config/ModConfig.java | 40 +++++++++++- .../client/network/CraftEnginePayload.java | 9 ++- .../fabric/CraftEngineFabricMod.java | 26 +++----- .../fabric/mixin/AbstractBlockStateMixin.java | 65 +++++++++++++++++++ .../fabric/mixin/AbstractRailBlockMixin.java | 26 ++++++++ .../fabric/mixin/BlockItemMixin.java | 27 ++++++++ .../fabric/mixin/FluidStateMixin.java | 26 ++++++++ .../craft-engine-fabric-mod/lang/en_us.json | 2 + .../craft-engine-fabric-mod/lang/zh_cn.json | 2 + .../main/resources/craftengine.mixins.json | 14 ++++ client-mod/src/main/resources/fabric.mod.json | 4 ++ 14 files changed, 305 insertions(+), 41 deletions(-) create mode 100644 client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java create mode 100644 client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java create mode 100644 client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java create mode 100644 client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java create mode 100644 client-mod/src/main/resources/craftengine.mixins.json 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 c35ecd914..755a10375 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 @@ -1962,28 +1962,48 @@ public class PacketConsumers { data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); } String decodeData = new String(data, StandardCharsets.UTF_8); - if (!decodeData.endsWith("init")) return; - int firstColon = decodeData.indexOf(':'); - if (firstColon == -1) return; - int secondColon = decodeData.indexOf(':', firstColon + 1); - if (secondColon == -1) return; - int clientBlockRegistrySize = Integer.parseInt(decodeData.substring(firstColon + 1, secondColon)); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft( - Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - ) - ) - ); - user.nettyChannel().writeAndFlush(kickPacket); - user.nettyChannel().disconnect(); - return; + if (decodeData.endsWith("init")) { + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + int clientBlockRegistrySize = Integer.parseInt(payloadData); + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (clientBlockRegistrySize != serverBlockRegistrySize) { + Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( + ComponentUtils.adventureToMinecraft( + Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + ) + ) + ); + user.nettyChannel().writeAndFlush(kickPacket); + user.nettyChannel().disconnect(); + return; + } + user.setClientModState(true); + } else if (decodeData.endsWith("cancel")) { + if (!VersionHelper.isOrAbove1_20_2()) return; + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + boolean cancel = Boolean.parseBoolean(payloadData); + if (cancel) { + user.nettyChannel().writeAndFlush( + Reflections.constructor$ClientboundCustomPayloadPacket.newInstance( + Reflections.constructor$DiscardedPayload.newInstance( + KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)), + (":true:cancel").getBytes(StandardCharsets.UTF_8) + ) + ) + ); + } } - user.setClientModState(true); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index b12714cee..679a26279 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6659,4 +6659,20 @@ public class Reflections { "world.entity.projectile.AbstractArrow" ) ); + + public static final Class clazz$ClientboundCustomPayloadPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + List.of("network.protocol.game.PacketPlayOutCustomPayload", "network.protocol.common.ClientboundCustomPayloadPacket"), + List.of("network.protocol.game.ClientboundCustomPayloadPacket", "network.protocol.common.ClientboundCustomPayloadPacket") + ) + ); + + public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( + ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundCustomPayloadPacket) + ); + + // 1.20.2+ + public static final Constructor constructor$DiscardedPayload = Optional.ofNullable(clazz$DiscardedPayload) + .map(clazz -> ReflectionUtils.getTheOnlyConstructor(clazz)) + .orElse(null); } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java index d3bdbf562..9dc5e6b27 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java @@ -1,9 +1,12 @@ package net.momirealms.craftengine.fabric.client; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.block.Block; @@ -20,8 +23,10 @@ import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload; import java.nio.charset.StandardCharsets; +@Environment(EnvType.CLIENT) public class CraftEngineFabricModClient implements ClientModInitializer { public static final String MOD_ID = "craftengine"; + public static boolean serverInstalled = false; @Override public void onInitializeClient() { @@ -29,6 +34,8 @@ public class CraftEngineFabricModClient implements ClientModInitializer { PayloadTypeRegistry.configurationC2S().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC); registerRenderLayer(); ClientConfigurationConnectionEvents.START.register(CraftEngineFabricModClient::initChannel); + ClientConfigurationNetworking.registerGlobalReceiver(CraftEnginePayload.ID, CraftEngineFabricModClient::handleReceiver); + ClientPlayConnectionEvents.DISCONNECT.register((client, handler) -> serverInstalled = false); } public static void registerRenderLayer() { @@ -60,12 +67,32 @@ public class CraftEngineFabricModClient implements ClientModInitializer { private static void initChannel(ClientConfigurationNetworkHandler handler, MinecraftClient client) { if (ModConfig.enableNetwork) { registerChannel(handler); + } else if (ModConfig.enableCancelBlockUpdate) { + registerCancelBlockUpdateChannel(handler); } else { ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID); } } + private static void handleReceiver(CraftEnginePayload payload, ClientConfigurationNetworking.Context context) { + byte[] data = payload.data(); + String decodeData = new String(data, StandardCharsets.UTF_8); + if (decodeData.endsWith("cancel")) { + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + serverInstalled = Boolean.parseBoolean(payloadData); + } + } + private static void registerChannel(ClientConfigurationNetworkHandler handler) { ClientConfigurationNetworking.send(new CraftEnginePayload((":" + Block.STATE_IDS.size() + ":init").getBytes(StandardCharsets.UTF_8))); } + + private static void registerCancelBlockUpdateChannel(ClientConfigurationNetworkHandler handler) { + ClientConfigurationNetworking.send(new CraftEnginePayload((":true:cancel").getBytes(StandardCharsets.UTF_8))); + + } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java index 6546896d6..6287d4e81 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java @@ -3,24 +3,35 @@ package net.momirealms.craftengine.fabric.client.config; import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; public class ModConfig { + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); public static boolean enableNetwork = true; + public static boolean enableCancelBlockUpdate = false; public static Screen getConfigScreen(Screen parent) { ConfigBuilder builder = ConfigBuilder.create() .setParentScreen(parent) + .setSavingRunnable(ModConfig::saveConfig) .setTitle(Text.translatable("title.craftengine.config")); ConfigCategory general = builder.getOrCreateCategory(Text.translatable("category.craftengine.general")); ConfigEntryBuilder entryBuilder = builder.entryBuilder(); general.addEntry(entryBuilder.startBooleanToggle( - Text.translatable("option.craftengine.enable_network") - .formatted(Formatting.WHITE), + Text.translatable("option.craftengine.enable_network") + .formatted(Formatting.WHITE), enableNetwork) .setDefaultValue(true) .setSaveConsumer(newValue -> enableNetwork = newValue) @@ -29,7 +40,32 @@ public class ModConfig { .formatted(Formatting.GRAY) ) .build()); + general.addEntry(entryBuilder.startBooleanToggle( + Text.translatable("option.craftengine.enable_cancel_block_update") + .formatted(Formatting.WHITE), + enableCancelBlockUpdate) + .setDefaultValue(false) + .setSaveConsumer(newValue -> enableCancelBlockUpdate = newValue) + .setTooltip( + Text.translatable("tooltip.craftengine.enable_cancel_block_update") + ) + .build() + ); return builder.build(); } + + private static void saveConfig() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + var data = new java.util.HashMap(); + data.put("enable-network", ModConfig.enableNetwork); + data.put("enable-cancel-block-update", ModConfig.enableCancelBlockUpdate); + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { + yaml.dump(data, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java index c975c1f7f..f55495fea 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java @@ -9,8 +9,13 @@ public record CraftEnginePayload(byte[] data) implements CustomPayload { public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload"); public static final Id ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD); public static final PacketCodec CODEC = PacketCodec.of( - (payload, byteBuf) -> byteBuf.writeByteArray(payload.data()), - buf -> new CraftEnginePayload(buf.readByteArray())); + (payload, byteBuf) -> byteBuf.writeBytes(payload.data()), + buf -> { + int i = buf.readableBytes(); + byte[] data = new byte[i]; + buf.readBytes(data); + return new CraftEnginePayload(data); + }); @Override public Id getId() { diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java index 90a2b995d..faf3c8e0e 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.fabric; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockState; @@ -9,16 +11,15 @@ import net.momirealms.craftengine.fabric.util.BlockUtils; import net.momirealms.craftengine.fabric.util.LoggerFilter; import net.momirealms.craftengine.fabric.util.RegisterBlocks; import net.momirealms.craftengine.fabric.util.YamlUtils; -import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import java.io.IOException; import java.io.InputStream; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; +@Environment(EnvType.CLIENT) public class CraftEngineFabricMod implements ModInitializer { private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); public static final String MOD_ID = "craftengine"; @@ -47,32 +48,25 @@ public class CraftEngineFabricMod implements ModInitializer { } catch (IOException e) { e.printStackTrace(); } - Runtime.getRuntime().addShutdownHook(new Thread(this::saveConfig)); } @SuppressWarnings("unchecked") private void loadConfig() { if (!Files.exists(CONFIG_PATH)) { ModConfig.enableNetwork = true; + ModConfig.enableCancelBlockUpdate = false; return; } try (InputStream inputStream = Files.newInputStream(CONFIG_PATH)) { Yaml yaml = new Yaml(); var config = yaml.loadAs(inputStream, java.util.Map.class); + if (config == null) { + ModConfig.enableNetwork = true; + ModConfig.enableCancelBlockUpdate = false; + return; + } ModConfig.enableNetwork = (Boolean) config.getOrDefault("enable-network", true); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void saveConfig() { - DumperOptions options = new DumperOptions(); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - Yaml yaml = new Yaml(options); - var data = new java.util.HashMap(); - data.put("enable-network", ModConfig.enableNetwork); - try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { - yaml.dump(data, writer); + ModConfig.enableCancelBlockUpdate = (Boolean) config.getOrDefault("enable-cancel-block-update", false); } catch (IOException e) { e.printStackTrace(); } diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java new file mode 100644 index 000000000..014869e0f --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; +import net.minecraft.world.block.WireOrientation; +import net.minecraft.world.tick.ScheduledTickView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(AbstractBlock.AbstractBlockState.class) +public abstract class AbstractBlockStateMixin { + + @Inject(method = "getStateForNeighborUpdate", at = @At("HEAD"), cancellable = true) + private void cancelGetStateForNeighborUpdate(WorldView world, ScheduledTickView tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, Random random, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(this); + } + + @Inject(method = "neighborUpdate", at = @At("HEAD"), cancellable = true) + private void cancelNeighborUpdate(World world, BlockPos pos, Block sourceBlock, WireOrientation wireOrientation, boolean notify, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "updateNeighbors*", at = @At("HEAD"), cancellable = true) + private void cancelUpdateNeighbors(WorldAccess world, BlockPos pos, int flags, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "scheduledTick", at = @At("HEAD"), cancellable = true) + private void cancelScheduledTick(ServerWorld world, BlockPos pos, Random random, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "canPlaceAt", at = @At("HEAD"), cancellable = true) + private void passCanPlaceAt(WorldView world, BlockPos pos, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(true); + } + + @Inject(method = "randomTick", at = @At("HEAD"), cancellable = true) + private void cancelRandomTick(ServerWorld world, BlockPos pos, Random random, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java new file mode 100644 index 000000000..1699baa52 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.AbstractRailBlock; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(AbstractRailBlock.class) +public abstract class AbstractRailBlockMixin { + + @Inject(method = "updateCurves", at = @At("HEAD"), cancellable = true) + private void cancelUpdateCurves(BlockState state, World world, BlockPos pos, boolean notify, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(state); + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java new file mode 100644 index 000000000..ba4c89546 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockItem.class) +public class BlockItemMixin { + + @Inject(method = "place*", at = @At("HEAD"), cancellable = true) + private void onPlace(ItemPlacementContext context, CallbackInfoReturnable cir) { + ItemStack stack = context.getStack(); + NbtComponent customData = stack.getComponents().get(DataComponentTypes.CUSTOM_DATA); + if (customData == null) return; + if (customData.contains("craftengine:id")) { + cir.setReturnValue(ActionResult.FAIL); + cir.cancel(); + } + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java new file mode 100644 index 000000000..695c89085 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.BlockState; +import net.minecraft.fluid.FluidState; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(FluidState.class) +public class FluidStateMixin { + + @Inject(method = "onScheduledTick", at = @At("HEAD"), cancellable = true) + private void cancelScheduledTick(ServerWorld world, BlockPos pos, BlockState state, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } +} diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json index 711d5c3ca..2eb9b4deb 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json @@ -2,6 +2,8 @@ "title.craftengine.config": "CraftEngine Settings", "category.craftengine.general": "General", "option.craftengine.enable_network": "Enable custom blocks in server", + "option.craftengine.enable_cancel_block_update": "Enable cancelling block updates in the server", "tooltip.craftengine.enable_network": "Changes requires re-entering the server to take effect", + "tooltip.craftengine.enable_cancel_block_update": "Only works on servers with CraftEngine installed.", "disconnect.craftengine.block_registry_mismatch": "Block registry size mismatch. Current: %s. Expected: %s. \n 1. Make sure that the configs are the same as the server's. \n 2. Do not use any mod that might register new block. \n 3. Do not install ViaVersion." } \ No newline at end of file diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json index c16c77c9d..e65e46887 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json @@ -2,6 +2,8 @@ "title.craftengine.config": "CraftEngine设置", "category.craftengine.general": "通用", "option.craftengine.enable_network": "启用服务器内自定义方块", + "option.craftengine.enable_cancel_block_update": "启用服务器内取消方块更新", "tooltip.craftengine.enable_network": "需要重新进入服务器以应用更改", + "tooltip.craftengine.enable_cancel_block_update": "仅在安装了CraftEngine的服务器内生效", "disconnect.craftengine.block_registry_mismatch": "方块注册表大小不匹配. 当前: %s. 预期: %s \n 1. 确保客户端mod配置与服务端配置一致. \n 2. 不要安装任何会注册新方块的mod. \n 3. 不要使用ViaVersion." } \ No newline at end of file diff --git a/client-mod/src/main/resources/craftengine.mixins.json b/client-mod/src/main/resources/craftengine.mixins.json new file mode 100644 index 000000000..be9dbe408 --- /dev/null +++ b/client-mod/src/main/resources/craftengine.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "net.momirealms.craftengine.fabric.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "AbstractBlockStateMixin", + "AbstractRailBlockMixin", + "BlockItemMixin", + "FluidStateMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/client-mod/src/main/resources/fabric.mod.json b/client-mod/src/main/resources/fabric.mod.json index fc6261618..785f8ed0d 100644 --- a/client-mod/src/main/resources/fabric.mod.json +++ b/client-mod/src/main/resources/fabric.mod.json @@ -24,6 +24,10 @@ "modmenu": ["net.momirealms.craftengine.fabric.client.config.ModMenuIntegration"] }, + "mixins": [ + "craftengine.mixins.json" + ], + "depends": { "fabricloader": ">=${loader_version}", "fabric": "*", From 26153b2096f5a1bff89c2eae0483f3044ddb6592 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 12 May 2025 15:07:00 +0800 Subject: [PATCH 47/73] =?UTF-8?q?feat(config):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B9=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/fabric/client/config/ModConfig.java | 4 ++-- .../momirealms/craftengine/fabric/CraftEngineFabricMod.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java index 6287d4e81..dc6689b15 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java @@ -17,7 +17,7 @@ import java.nio.file.Path; public class ModConfig { private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); - public static boolean enableNetwork = true; + public static boolean enableNetwork = false; public static boolean enableCancelBlockUpdate = false; public static Screen getConfigScreen(Screen parent) { @@ -33,7 +33,7 @@ public class ModConfig { Text.translatable("option.craftengine.enable_network") .formatted(Formatting.WHITE), enableNetwork) - .setDefaultValue(true) + .setDefaultValue(false) .setSaveConsumer(newValue -> enableNetwork = newValue) .setTooltip( Text.translatable("tooltip.craftengine.enable_network") diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java index faf3c8e0e..94abd5b8a 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java @@ -53,7 +53,7 @@ public class CraftEngineFabricMod implements ModInitializer { @SuppressWarnings("unchecked") private void loadConfig() { if (!Files.exists(CONFIG_PATH)) { - ModConfig.enableNetwork = true; + ModConfig.enableNetwork = false; ModConfig.enableCancelBlockUpdate = false; return; } @@ -61,11 +61,11 @@ public class CraftEngineFabricMod implements ModInitializer { Yaml yaml = new Yaml(); var config = yaml.loadAs(inputStream, java.util.Map.class); if (config == null) { - ModConfig.enableNetwork = true; + ModConfig.enableNetwork = false; ModConfig.enableCancelBlockUpdate = false; return; } - ModConfig.enableNetwork = (Boolean) config.getOrDefault("enable-network", true); + ModConfig.enableNetwork = (Boolean) config.getOrDefault("enable-network", false); ModConfig.enableCancelBlockUpdate = (Boolean) config.getOrDefault("enable-cancel-block-update", false); } catch (IOException e) { e.printStackTrace(); From bac058a92649654b839d13add8bfa51c476c1a2c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 12 May 2025 16:18:53 +0800 Subject: [PATCH 48/73] =?UTF-8?q?feat(config):=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/fabric/mixin/BlockItemMixin.java | 3 +++ client-mod/src/main/resources/craftengine.mixins.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java index ba4c89546..fe3d3a6a8 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.fabric.mixin; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.NbtComponent; import net.minecraft.item.BlockItem; @@ -11,6 +13,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +@Environment(EnvType.CLIENT) @Mixin(BlockItem.class) public class BlockItemMixin { diff --git a/client-mod/src/main/resources/craftengine.mixins.json b/client-mod/src/main/resources/craftengine.mixins.json index be9dbe408..d177f9a82 100644 --- a/client-mod/src/main/resources/craftengine.mixins.json +++ b/client-mod/src/main/resources/craftengine.mixins.json @@ -2,7 +2,7 @@ "required": true, "package": "net.momirealms.craftengine.fabric.mixin", "compatibilityLevel": "JAVA_21", - "mixins": [ + "client": [ "AbstractBlockStateMixin", "AbstractRailBlockMixin", "BlockItemMixin", From 82e8fc5263ed05b9a7ca5985a4b01f2b9851dd02 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 12 May 2025 16:58:41 +0800 Subject: [PATCH 49/73] =?UTF-8?q?feat(config):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=92=8C=E8=A7=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/NetWorkDataTypes.java | 36 ++++++++++++++ .../plugin/network/PacketConsumers.java | 37 +++++--------- .../client/CraftEngineFabricModClient.java | 48 +++++++++---------- .../fabric/client/util/NetWorkDataTypes.java | 35 ++++++++++++++ .../core/util/FriendlyByteBuf.java | 9 ++++ 5 files changed, 117 insertions(+), 48 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java create mode 100644 client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java new file mode 100644 index 000000000..db3af3c0d --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.bukkit.plugin.network; + + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public enum NetWorkDataTypes { + CLIENT_CUSTOM_BLOCK( + FriendlyByteBuf::readInt, + FriendlyByteBuf::writeInt + ), + CANCEL_BLOCK_UPDATE( + FriendlyByteBuf::readBoolean, + FriendlyByteBuf::writeBoolean + ); + + private final Function decoder; + private final BiConsumer encoder; + + @SuppressWarnings("unchecked") + NetWorkDataTypes(Function decoder, BiConsumer encoder) { + this.decoder = decoder; + this.encoder = (buf, data) -> encoder.accept(buf, (T) data); + } + + @SuppressWarnings("unchecked") + public T decode(FriendlyByteBuf buf) { + return (T) decoder.apply(buf); + } + + public void encode(FriendlyByteBuf buf, T data) { + encoder.accept(buf, data); + } +} 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 755a10375..680391068 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 @@ -1961,14 +1961,10 @@ public class PacketConsumers { } else { data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); } - String decodeData = new String(data, StandardCharsets.UTF_8); - if (decodeData.endsWith("init")) { - int firstColon = decodeData.indexOf(':'); - if (firstColon == -1) return; - int secondColon = decodeData.indexOf(':', firstColon + 1); - if (secondColon == -1) return; - String payloadData = decodeData.substring(firstColon + 1, secondColon); - int clientBlockRegistrySize = Integer.parseInt(payloadData); + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(data)); + NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); + if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { + int clientBlockRegistrySize = dataType.decode(buf); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); if (clientBlockRegistrySize != serverBlockRegistrySize) { Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( @@ -1985,23 +1981,16 @@ public class PacketConsumers { return; } user.setClientModState(true); - } else if (decodeData.endsWith("cancel")) { + } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { if (!VersionHelper.isOrAbove1_20_2()) return; - int firstColon = decodeData.indexOf(':'); - if (firstColon == -1) return; - int secondColon = decodeData.indexOf(':', firstColon + 1); - if (secondColon == -1) return; - String payloadData = decodeData.substring(firstColon + 1, secondColon); - boolean cancel = Boolean.parseBoolean(payloadData); - if (cancel) { - user.nettyChannel().writeAndFlush( - Reflections.constructor$ClientboundCustomPayloadPacket.newInstance( - Reflections.constructor$DiscardedPayload.newInstance( - KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)), - (":true:cancel").getBytes(StandardCharsets.UTF_8) - ) - ) - ); + if (dataType.decode(buf)) { + FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); + bufPayload.writeEnumConstant(dataType); + dataType.encode(bufPayload, true); + Object channelKey = KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)); + Object dataPayload = Reflections.constructor$DiscardedPayload.newInstance(channelKey, bufPayload.array()); + Object responsePacket = Reflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); + user.nettyChannel().writeAndFlush(responsePacket); } } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java index 9dc5e6b27..b0c300d51 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.fabric.client; +import io.netty.buffer.Unpooled; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -14,14 +15,14 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.color.world.BiomeColors; import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.client.render.RenderLayer; +import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; import net.minecraft.world.biome.FoliageColors; import net.momirealms.craftengine.fabric.client.blocks.CustomBlock; import net.momirealms.craftengine.fabric.client.config.ModConfig; import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload; - -import java.nio.charset.StandardCharsets; +import net.momirealms.craftengine.fabric.client.util.NetWorkDataTypes; @Environment(EnvType.CLIENT) public class CraftEngineFabricModClient implements ClientModInitializer { @@ -65,34 +66,33 @@ public class CraftEngineFabricModClient implements ClientModInitializer { } private static void initChannel(ClientConfigurationNetworkHandler handler, MinecraftClient client) { - if (ModConfig.enableNetwork) { - registerChannel(handler); - } else if (ModConfig.enableCancelBlockUpdate) { - registerCancelBlockUpdateChannel(handler); - } else { + if (!ModConfig.enableNetwork && !ModConfig.enableCancelBlockUpdate) { ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID); + return; } + + NetWorkDataTypes type = ModConfig.enableNetwork + ? NetWorkDataTypes.CLIENT_CUSTOM_BLOCK + : NetWorkDataTypes.CANCEL_BLOCK_UPDATE; + + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeEnumConstant(type); + + if (ModConfig.enableNetwork) { + type.encode(buf, Block.STATE_IDS.size()); + } else if (ModConfig.enableCancelBlockUpdate) { + type.encode(buf, true); + } + + ClientConfigurationNetworking.send(new CraftEnginePayload(buf.array())); } private static void handleReceiver(CraftEnginePayload payload, ClientConfigurationNetworking.Context context) { byte[] data = payload.data(); - String decodeData = new String(data, StandardCharsets.UTF_8); - if (decodeData.endsWith("cancel")) { - int firstColon = decodeData.indexOf(':'); - if (firstColon == -1) return; - int secondColon = decodeData.indexOf(':', firstColon + 1); - if (secondColon == -1) return; - String payloadData = decodeData.substring(firstColon + 1, secondColon); - serverInstalled = Boolean.parseBoolean(payloadData); + PacketByteBuf buf = new PacketByteBuf(Unpooled.wrappedBuffer(data)); + NetWorkDataTypes type = buf.readEnumConstant(NetWorkDataTypes.class); + if (type == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { + serverInstalled = type.decode(buf); } } - - private static void registerChannel(ClientConfigurationNetworkHandler handler) { - ClientConfigurationNetworking.send(new CraftEnginePayload((":" + Block.STATE_IDS.size() + ":init").getBytes(StandardCharsets.UTF_8))); - } - - private static void registerCancelBlockUpdateChannel(ClientConfigurationNetworkHandler handler) { - ClientConfigurationNetworking.send(new CraftEnginePayload((":true:cancel").getBytes(StandardCharsets.UTF_8))); - - } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java new file mode 100644 index 000000000..e299b41eb --- /dev/null +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java @@ -0,0 +1,35 @@ +package net.momirealms.craftengine.fabric.client.util; + +import net.minecraft.network.PacketByteBuf; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public enum NetWorkDataTypes { + CLIENT_CUSTOM_BLOCK( + PacketByteBuf::readInt, + PacketByteBuf::writeInt + ), + CANCEL_BLOCK_UPDATE( + PacketByteBuf::readBoolean, + PacketByteBuf::writeBoolean + ); + + private final Function decoder; + private final BiConsumer encoder; + + @SuppressWarnings("unchecked") + NetWorkDataTypes(Function decoder, BiConsumer encoder) { + this.decoder = decoder; + this.encoder = (buf, data) -> encoder.accept(buf, (T) data); + } + + @SuppressWarnings("unchecked") + public T decode(PacketByteBuf buf) { + return (T) decoder.apply(buf); + } + + public void encode(PacketByteBuf buf, T data) { + encoder.accept(buf, data); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java index 5219bb4b4..8f12573cb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java @@ -458,6 +458,15 @@ public class FriendlyByteBuf extends ByteBuf { this.writeBytes(Arrays.copyOf(byteArray, MCUtils.positiveCeilDiv(size, 8))); } + @SuppressWarnings("unchecked") + public > T readEnumConstant(Class enumClass) { + return (T)((Enum[])enumClass.getEnumConstants())[this.readVarInt()]; + } + + public FriendlyByteBuf writeEnumConstant(Enum instance) { + return this.writeVarInt(instance.ordinal()); + } + @FunctionalInterface public interface Writer extends BiConsumer { From c4a79ea43dfe3cf12422590caf0ce02e9edfea96 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 12 May 2025 18:07:48 +0800 Subject: [PATCH 50/73] =?UTF-8?q?feat(config):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=92=8C=E8=A7=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/NetWorkDataTypes.java | 66 +++++++++++++------ .../plugin/network/PacketConsumers.java | 10 +-- .../client/CraftEngineFabricModClient.java | 13 ++-- .../fabric/client/util/NetWorkDataTypes.java | 66 +++++++++++++------ 4 files changed, 105 insertions(+), 50 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java index db3af3c0d..50b8e57bf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java @@ -3,34 +3,62 @@ package net.momirealms.craftengine.bukkit.plugin.network; import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import java.util.HashMap; +import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Function; -public enum NetWorkDataTypes { - CLIENT_CUSTOM_BLOCK( - FriendlyByteBuf::readInt, - FriendlyByteBuf::writeInt - ), - CANCEL_BLOCK_UPDATE( - FriendlyByteBuf::readBoolean, - FriendlyByteBuf::writeBoolean - ); +public class NetWorkDataTypes { + private static final Map> id2NetWorkDataTypes = new HashMap<>(); - private final Function decoder; - private final BiConsumer encoder; + public static final NetWorkDataTypes CLIENT_CUSTOM_BLOCK = + new NetWorkDataTypes<>(0, FriendlyByteBuf::readInt, FriendlyByteBuf::writeInt); - @SuppressWarnings("unchecked") - NetWorkDataTypes(Function decoder, BiConsumer encoder) { + public static final NetWorkDataTypes CANCEL_BLOCK_UPDATE = + new NetWorkDataTypes<>(1, FriendlyByteBuf::readBoolean, FriendlyByteBuf::writeBoolean); + + static { + register(CLIENT_CUSTOM_BLOCK); + register(CANCEL_BLOCK_UPDATE); + } + + private static void register(NetWorkDataTypes type) { + id2NetWorkDataTypes.put(type.id, type); + } + + private final int id; + private final Function decoder; + private final BiConsumer encoder; + + public NetWorkDataTypes(int id, Function decoder, BiConsumer encoder) { + this.id = id; this.decoder = decoder; - this.encoder = (buf, data) -> encoder.accept(buf, (T) data); + this.encoder = encoder; } - @SuppressWarnings("unchecked") - public T decode(FriendlyByteBuf buf) { - return (T) decoder.apply(buf); + public T decode(FriendlyByteBuf buf) { + return decoder.apply(buf); } - public void encode(FriendlyByteBuf buf, T data) { + public void encode(FriendlyByteBuf buf, T data) { encoder.accept(buf, data); } -} + + public int id() { + return id; + } + + public void writeType(FriendlyByteBuf buf) { + buf.writeVarInt(id); + } + + public static NetWorkDataTypes readType(FriendlyByteBuf buf) { + int id = buf.readVarInt(); + return id2NetWorkDataTypes.get(id); + } + + @SuppressWarnings("unchecked") + public NetWorkDataTypes as(Class clazz) { + return (NetWorkDataTypes) this; + } +} \ No newline at end of file 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 680391068..cec73f88d 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 @@ -1962,9 +1962,9 @@ public class PacketConsumers { data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); } FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(data)); - NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); + NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.decode(buf); + int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); if (clientBlockRegistrySize != serverBlockRegistrySize) { Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( @@ -1983,10 +1983,10 @@ public class PacketConsumers { user.setClientModState(true); } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { if (!VersionHelper.isOrAbove1_20_2()) return; - if (dataType.decode(buf)) { + if (dataType.as(Boolean.class).decode(buf)) { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - bufPayload.writeEnumConstant(dataType); - dataType.encode(bufPayload, true); + dataType.writeType(bufPayload); + dataType.as(Boolean.class).encode(bufPayload, true); Object channelKey = KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)); Object dataPayload = Reflections.constructor$DiscardedPayload.newInstance(channelKey, bufPayload.array()); Object responsePacket = Reflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java index b0c300d51..ed32e3bda 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java @@ -71,16 +71,15 @@ public class CraftEngineFabricModClient implements ClientModInitializer { return; } - NetWorkDataTypes type = ModConfig.enableNetwork - ? NetWorkDataTypes.CLIENT_CUSTOM_BLOCK - : NetWorkDataTypes.CANCEL_BLOCK_UPDATE; - PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); - buf.writeEnumConstant(type); if (ModConfig.enableNetwork) { + NetWorkDataTypes type = NetWorkDataTypes.CLIENT_CUSTOM_BLOCK; + type.writeType(buf); type.encode(buf, Block.STATE_IDS.size()); } else if (ModConfig.enableCancelBlockUpdate) { + NetWorkDataTypes type = NetWorkDataTypes.CANCEL_BLOCK_UPDATE; + type.writeType(buf); type.encode(buf, true); } @@ -90,9 +89,9 @@ public class CraftEngineFabricModClient implements ClientModInitializer { private static void handleReceiver(CraftEnginePayload payload, ClientConfigurationNetworking.Context context) { byte[] data = payload.data(); PacketByteBuf buf = new PacketByteBuf(Unpooled.wrappedBuffer(data)); - NetWorkDataTypes type = buf.readEnumConstant(NetWorkDataTypes.class); + NetWorkDataTypes type = NetWorkDataTypes.readType(buf); if (type == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - serverInstalled = type.decode(buf); + serverInstalled = type.as(Boolean.class).decode(buf); } } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java index e299b41eb..63c8bf8be 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java @@ -2,34 +2,62 @@ package net.momirealms.craftengine.fabric.client.util; import net.minecraft.network.PacketByteBuf; +import java.util.HashMap; +import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Function; -public enum NetWorkDataTypes { - CLIENT_CUSTOM_BLOCK( - PacketByteBuf::readInt, - PacketByteBuf::writeInt - ), - CANCEL_BLOCK_UPDATE( - PacketByteBuf::readBoolean, - PacketByteBuf::writeBoolean - ); +public class NetWorkDataTypes { + private static final Map> id2NetWorkDataTypes = new HashMap<>(); - private final Function decoder; - private final BiConsumer encoder; + public static final NetWorkDataTypes CLIENT_CUSTOM_BLOCK = + new NetWorkDataTypes<>(0, PacketByteBuf::readInt, PacketByteBuf::writeInt); - @SuppressWarnings("unchecked") - NetWorkDataTypes(Function decoder, BiConsumer encoder) { + public static final NetWorkDataTypes CANCEL_BLOCK_UPDATE = + new NetWorkDataTypes<>(1, PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean); + + static { + register(CLIENT_CUSTOM_BLOCK); + register(CANCEL_BLOCK_UPDATE); + } + + private static void register(NetWorkDataTypes type) { + id2NetWorkDataTypes.put(type.id, type); + } + + private final int id; + private final Function decoder; + private final BiConsumer encoder; + + public NetWorkDataTypes(int id, Function decoder, BiConsumer encoder) { + this.id = id; this.decoder = decoder; - this.encoder = (buf, data) -> encoder.accept(buf, (T) data); + this.encoder = encoder; } - @SuppressWarnings("unchecked") - public T decode(PacketByteBuf buf) { - return (T) decoder.apply(buf); + public T decode(PacketByteBuf buf) { + return decoder.apply(buf); } - public void encode(PacketByteBuf buf, T data) { + public void encode(PacketByteBuf buf, T data) { encoder.accept(buf, data); } -} + + public int id() { + return id; + } + + public void writeType(PacketByteBuf buf) { + buf.writeVarInt(id); + } + + public static NetWorkDataTypes readType(PacketByteBuf buf) { + int id = buf.readVarInt(); + return id2NetWorkDataTypes.get(id); + } + + @SuppressWarnings("unchecked") + public NetWorkDataTypes as(Class clazz) { + return (NetWorkDataTypes) this; + } +} \ No newline at end of file From 2731ce4d71be58d40d080dfbb751a4951b75ff09 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 22:57:29 +0800 Subject: [PATCH 51/73] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++-- bukkit/build.gradle.kts | 2 +- bukkit/legacy/build.gradle.kts | 2 +- bukkit/loader/build.gradle.kts | 8 +-- .../item/listener/ItemEventListener.java | 9 ++- .../classpath/BukkitClassPathAppender.java | 38 +++++++++++++ .../plugin/user/BukkitServerPlayer.java | 3 +- .../craftengine/bukkit/util/Reflections.java | 9 +++ client-mod/build.gradle.kts | 2 +- core/build.gradle.kts | 6 +- server-mod/v1_20_1/build.gradle.kts | 2 +- server-mod/v1_20_5/build.gradle.kts | 2 +- server-mod/v1_21_5/build.gradle.kts | 2 +- .../mod/block/CraftEngineBlock.java | 57 +++++++------------ .../shared/block/BlockBehavior.java | 8 +++ 15 files changed, 103 insertions(+), 58 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/BukkitClassPathAppender.java diff --git a/README.md b/README.md index fefff6da4..941fceae5 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,14 @@

- - Gitbook - - Scc Count Badge + Scc Count Badge + + + Ask DeepWiki + + + Gitbook

diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 607fff3b3..8e5ae6b27 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" id("maven-publish") } diff --git a/bukkit/legacy/build.gradle.kts b/bukkit/legacy/build.gradle.kts index ae80f6f46..da89d9df8 100644 --- a/bukkit/legacy/build.gradle.kts +++ b/bukkit/legacy/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" } repositories { diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index dae694cd2..83ddf1699 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta11" - id("net.minecrell.plugin-yml.bukkit") version "0.6.0" + id("com.gradleup.shadow") version "9.0.0-beta13" + id("de.eldoria.plugin-yml.bukkit") version "0.7.1" } repositories { @@ -25,7 +25,7 @@ dependencies { implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") - implementation("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") + compileOnly("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") } java { @@ -60,7 +60,7 @@ artifacts { tasks { shadowJar { - archiveFileName = "${rootProject.name}-plugin-${rootProject.properties["project_version"]}.jar" + archiveFileName = "${rootProject.name}-bukkit-plugin-${rootProject.properties["project_version"]}.jar" destinationDirectory.set(file("$rootDir/target")) relocate("net.kyori", "net.momirealms.craftengine.libraries") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") 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 18d04e54c..31e379b78 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 @@ -122,6 +122,7 @@ public class ItemEventListener implements Listener { Block clickedBlock = Objects.requireNonNull(event.getClickedBlock()); BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer); InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + // 如果同一tick已经处理过交互,则忽略 if (cancelEventIfHasInteraction(event, player, hand)) { return; } @@ -132,6 +133,7 @@ public class ItemEventListener implements Listener { Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); // has custom item behavior + // 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为 if (optionalItemBehaviors.isPresent()) { BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation()); Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); @@ -140,12 +142,17 @@ public class ItemEventListener implements Listener { boolean interactable = InteractUtils.isInteractable(BlockStateUtils.getBlockOwnerId(clickedBlock), bukkitPlayer, clickedBlock.getBlockData(), hitResult, itemInHand); // do not allow to place block if it's a vanilla block + // 如果这个是自定义物品,那么会阻止玩家放置其对应的原版方块 Optional> optionalCustomItem = itemInHand.getCustomItem(); if (itemInHand.isBlockItem() && optionalCustomItem.isPresent()) { // it's a custom item, but now it's ignored + // 如果用户设置了允许放置对应的原版方块,那么直接返回。 + // todo 实际上这里的处理并不正确,因为判断玩家是否能够放置那个方块需要更加细节的判断。比如玩家无法对着树叶放置火把,但是交互事件依然触发,此情况下不可丢弃自定义行为。 if (optionalCustomItem.get().settings().canPlaceRelatedVanillaBlock()) { return; } + // 如果玩家潜行放置或者交互对象不可交互,那么取消掉事件以防止玩家放置。 + // todo 这些处理应该要搬到BlockPlaceEvent? if (!interactable || player.isSecondaryUseActive()) { event.setCancelled(true); } @@ -180,10 +187,10 @@ public class ItemEventListener implements Listener { return; } } - return; } // it's a vanilla block + // 这部分代码是处理放置原版方块“缺失的”声音和挥手动画 if (itemInHand.isBlockItem() && !itemInHand.isCustomItem()) { // client won't have sounds if the fake block is interactable // so we should check and resend sounds on interact diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/BukkitClassPathAppender.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/BukkitClassPathAppender.java new file mode 100644 index 000000000..ddb3b04da --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/classpath/BukkitClassPathAppender.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.bukkit.plugin.classpath; + +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.plugin.Plugin; +import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; +import net.momirealms.craftengine.core.plugin.classpath.URLClassLoaderAccess; + +import java.net.MalformedURLException; +import java.net.URLClassLoader; +import java.nio.file.Path; + +public class BukkitClassPathAppender implements ClassPathAppender { + private final URLClassLoaderAccess classLoaderAccess; + + public BukkitClassPathAppender(ClassLoader classLoader) throws IllegalAccessException { + if (Reflections.clazz$PaperPluginClassLoader != null && Reflections.clazz$PaperPluginClassLoader.isInstance(classLoader)) { + URLClassLoader libraryClassLoader = (URLClassLoader) Reflections.field$PaperPluginClassLoader$libraryLoader.get(classLoader); + this.classLoaderAccess = URLClassLoaderAccess.create(libraryClassLoader); + } else if (classLoader instanceof URLClassLoader) { + this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) classLoader); + } else { + throw new IllegalStateException("ClassLoader is not instance of URLClassLoader"); + } + } + + public BukkitClassPathAppender(Plugin plugin) throws IllegalAccessException { + this(plugin.getClass().getClassLoader()); + } + + @Override + public void addJarToClasspath(Path file) { + try { + this.classLoaderAccess.addURL(file.toUri().toURL()); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } +} 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 b1f33c52d..590515847 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 @@ -317,7 +317,6 @@ public class BukkitServerPlayer extends Player { public void tick() { // not fully online if (serverPlayer() == null) return; - if (VersionHelper.isFolia()) { try { Object serverPlayer = serverPlayer(); @@ -329,7 +328,7 @@ public class BukkitServerPlayer extends Player { } else { this.gameTicks = FastNMS.INSTANCE.field$MinecraftServer$currentTick(); } - if (this.gameTicks % 15 == 0) { + if (this.gameTicks % 30 == 0) { this.updateGUI(); } if (this.isDestroyingBlock) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 679a26279..cf7abd95b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -27,6 +27,7 @@ import sun.misc.Unsafe; import java.io.BufferedReader; import java.lang.invoke.VarHandle; import java.lang.reflect.*; +import java.net.URLClassLoader; import java.time.Instant; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -6675,4 +6676,12 @@ public class Reflections { public static final Constructor constructor$DiscardedPayload = Optional.ofNullable(clazz$DiscardedPayload) .map(clazz -> ReflectionUtils.getTheOnlyConstructor(clazz)) .orElse(null); + + public static final Class clazz$PaperPluginClassLoader = ReflectionUtils.getClazz( + "io.papermc.paper.plugin.entrypoint.classloader.PaperPluginClassLoader" + ); + + public static final Field field$PaperPluginClassLoader$libraryLoader = Optional.ofNullable(clazz$PaperPluginClassLoader) + .map(it -> ReflectionUtils.getDeclaredField(it, URLClassLoader.class, 0)) + .orElse(null); } diff --git a/client-mod/build.gradle.kts b/client-mod/build.gradle.kts index df2efc2e3..083cc7ad4 100644 --- a/client-mod/build.gradle.kts +++ b/client-mod/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("fabric-loom") version "1.10-SNAPSHOT" - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" } version = property("project_version")!! diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 83e995a17..8b6a644d8 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" id("maven-publish") } @@ -52,9 +52,7 @@ dependencies { // Aho-Corasick java implementation compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") // Amazon S3 - compileOnly("software.amazon.awssdk:s3:${rootProject.properties["amazon_awssdk_version"]}") { - - } + compileOnly("software.amazon.awssdk:s3:${rootProject.properties["amazon_awssdk_version"]}") compileOnly("software.amazon.awssdk:netty-nio-client:${rootProject.properties["amazon_awssdk_version"]}") // EvalEx compileOnly("com.ezylang:EvalEx:${rootProject.properties["evalex_version"]}") diff --git a/server-mod/v1_20_1/build.gradle.kts b/server-mod/v1_20_1/build.gradle.kts index 8589cbe10..0266dd510 100644 --- a/server-mod/v1_20_1/build.gradle.kts +++ b/server-mod/v1_20_1/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("java-library") - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" } diff --git a/server-mod/v1_20_5/build.gradle.kts b/server-mod/v1_20_5/build.gradle.kts index 272257de9..db31453d2 100644 --- a/server-mod/v1_20_5/build.gradle.kts +++ b/server-mod/v1_20_5/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("java-library") - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" } diff --git a/server-mod/v1_21_5/build.gradle.kts b/server-mod/v1_21_5/build.gradle.kts index 0be3a008a..617f52ce2 100644 --- a/server-mod/v1_21_5/build.gradle.kts +++ b/server-mod/v1_21_5/build.gradle.kts @@ -1,6 +1,6 @@ plugins { id("java-library") - id("com.gradleup.shadow") version "9.0.0-beta11" + id("com.gradleup.shadow") version "9.0.0-beta13" id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 8b3039c7b..cec744de3 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -5,13 +5,18 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; @@ -23,7 +28,6 @@ import org.jetbrains.annotations.NotNull; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock - //TODO , SimpleWaterloggedBlock { private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState()); private boolean isNoteBlock; @@ -146,14 +150,14 @@ public class CraftEngineBlock } @Override - protected BlockState updateShape(@NotNull BlockState state, - @NotNull LevelReader level, - @NotNull ScheduledTickAccess scheduledTickAccess, - @NotNull BlockPos pos, - @NotNull Direction direction, - @NotNull BlockPos neighborPos, - @NotNull BlockState neighborState, - @NotNull RandomSource random) { + protected @NotNull BlockState updateShape(@NotNull BlockState state, + @NotNull LevelReader level, + @NotNull ScheduledTickAccess scheduledTickAccess, + @NotNull BlockPos pos, + @NotNull Direction direction, + @NotNull BlockPos neighborPos, + @NotNull BlockState neighborState, + @NotNull RandomSource random) { try { if (isNoteBlock && level instanceof ServerLevel serverLevel) { startNoteBlockChain(direction, serverLevel, pos); @@ -189,16 +193,6 @@ public class CraftEngineBlock } } -// @Override -// protected @NotNull FluidState getFluidState(@NotNull BlockState state) { -// try { -// return (FluidState) behaviorHolder.value().getFluidState(this, new Object[]{state}, () -> super.getFluidState(state)); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.getFluidState(state); -// } -// } - @Override public boolean isValidBonemealTarget(@NotNull LevelReader levelReader, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { @@ -236,35 +230,24 @@ public class CraftEngineBlock e.printStackTrace(); } } - +// // @Override -// public boolean canPlaceLiquid(@Nullable Player player, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Fluid fluid) { +// protected @NotNull InteractionResult useWithoutItem(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull BlockHitResult hitResult) { // try { -// return behaviorHolder.value().canPlaceLiquid(this, new Object[]{player, level, pos, state, fluid}, () -> SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid)); +// return (InteractionResult) behaviorHolder.value().useWithoutItem(this, new Object[]{state, level, pos, player, hitResult}, () -> super.useWithoutItem(state, level, pos, player, hitResult)); // } catch (Exception e) { // e.printStackTrace(); -// return SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid); +// return super.useWithoutItem(state, level, pos, player, hitResult); // } // } // // @Override -// public boolean placeLiquid(@NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull FluidState fluidState) { +// protected @NotNull InteractionResult useItemOn(@NotNull ItemStack stack, @NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) { // try { -// return behaviorHolder.value().placeLiquid(this, new Object[]{level, pos, state, fluidState}, () -> SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState)); +// return (InteractionResult) behaviorHolder.value().useItemOn(this, new Object[]{stack, stack, level, pos, player, hand, hitResult}, () -> super.useItemOn(stack, state, level, pos, player, hand, hitResult)); // } catch (Exception e) { // e.printStackTrace(); -// return SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState); -// } -// } -// -// @NotNull -// @Override -// public ItemStack pickupBlock(@Nullable Player player, @NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state) { -// try { -// return (ItemStack) behaviorHolder.value().pickupBlock(this, new Object[]{player, level, pos, state}, () -> SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state); +// return super.useItemOn(stack, state, level, pos, player, hand, hitResult); // } // } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index 67c22fbd8..c48115996 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -4,6 +4,14 @@ import java.util.concurrent.Callable; public abstract class BlockBehavior { +// public Object useItemOn(Object thisBlock, Object[] args, Callable superMethod) throws Exception { +// return superMethod.call(); +// } +// +// public Object useWithoutItem(Object thisBlock, Object[] args, Callable superMethod) throws Exception { +// return superMethod.call(); +// } + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return superMethod.call(); } From 921efc8fea8419c59942dd342d88dae713665f35 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 23:26:54 +0800 Subject: [PATCH 52/73] Update build.gradle.kts --- bukkit/loader/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 83ddf1699..6be000e1a 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") - compileOnly("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") + implementation("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") } java { From b176eeafea996104c7d8e6d4eba0542cc840140c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 12 May 2025 23:47:22 +0800 Subject: [PATCH 53/73] Update fix_client_visual.yml --- .../resources/default/configuration/fix_client_visual.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml index f9d659368..9e18aabaf 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/fix_client_visual.yml @@ -23,4 +23,5 @@ blocks: minecraft:note_block: settings: client-bound-tags: - - minecraft:beacon_base_blocks \ No newline at end of file + - minecraft:beacon_base_blocks + - minecraft:mineable/axe \ No newline at end of file From 748cf572e841c26388b5a6396a98736466a5adfa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 13 May 2025 02:44:57 +0800 Subject: [PATCH 54/73] =?UTF-8?q?=E5=A5=A0=E5=AE=9Aevents=E5=9F=BA?= =?UTF-8?q?=E7=A1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 2 + .../bukkit/block/BukkitBlockManager.java | 85 +++--- .../bukkit/item/behavior/AxeItemBehavior.java | 2 +- .../item/behavior/BlockItemBehavior.java | 55 ++-- .../item/factory/BukkitItemFactory.java | 1 + .../item/listener/ItemEventListener.java | 267 +++++++++--------- .../plugin/command/feature/TestCommand.java | 1 - .../bukkit/util/BlockStateUtils.java | 15 +- .../bukkit/util/InteractUtils.java | 7 +- .../craftengine/bukkit/util/TagUtils.java | 1 - .../core/block/BlockRegistryMirror.java | 6 +- .../craftengine/core/block/CustomBlock.java | 6 + .../core/block/ImmutableBlockState.java | 10 +- .../craftengine/core/loot/LootContext.java | 10 - .../context/condition/ClickTypeCondition.java | 44 +++ .../context/condition/CommonConditions.java | 1 + .../function/AbstractConditionalFunction.java | 4 +- .../context/function/FunctionFactory.java | 10 + .../number/ExpressionNumberProvider.java | 3 +- .../context/number/FixedNumberProvider.java | 3 +- .../context/number/NumberProviderFactory.java | 8 + .../context/number/NumberProviders.java | 7 +- .../context/number/UniformNumberProvider.java | 3 +- .../context/parameter/CommonParameters.java | 2 + .../context/selector/PlayerSelectors.java | 3 + .../plugin/event/BlockEventConditions.java | 32 ++- .../plugin/event/BlockEventFunctions.java | 8 +- .../core/plugin/event/EventTrigger.java | 36 ++- .../core/registry/BuiltInRegistries.java | 12 +- .../craftengine/core/registry/Registries.java | 12 +- .../craftengine/core/util/ClickType.java | 5 + .../craftengine/core/util/Factory.java | 8 - .../mod/block/CraftEngineBlock.java | 107 +++---- .../mod/block/CraftEngineBlock.java | 123 +++----- .../mod/block/CraftEngineBlock.java | 86 ++---- .../shared/block/BlockBehavior.java | 24 -- 36 files changed, 507 insertions(+), 502 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/FunctionFactory.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviderFactory.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/ClickType.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/Factory.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 4c2938cb0..456d2405d 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -90,6 +90,7 @@ warning.config.condition.match_block_property.missing_properties: "Issue warning.config.condition.match_item.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'match_item' condition." warning.config.condition.table_bonus.missing_enchantment: "Issue found in file - The config '' is missing the required 'enchantment' argument for 'table_bonus' condition." warning.config.condition.table_bonus.missing_chances: "Issue found in file - The config '' is missing the required 'chances' argument for 'table_bonus' condition." +warning.config.condition.click_type.missing_click_type: "Issue found in file - The config '' is missing the required 'click-type' argument for 'click_type' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -298,4 +299,5 @@ warning.config.conflict_matcher.any_of.missing_terms: "Issue found in co warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." +warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 5e8d9a78a..84f1098d6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -31,7 +31,6 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; @@ -49,7 +48,6 @@ import java.io.File; import java.lang.reflect.Field; import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; public class BukkitBlockManager extends AbstractBlockManager { private static BukkitBlockManager instance; @@ -252,7 +250,7 @@ public class BukkitBlockManager extends AbstractBlockManager { for (int i = 0; i < size; i++) { states[i] = new PackedBlockState(BlockStateUtils.idToBlockState(i), i); } - BlockRegistryMirror.init(states); + BlockRegistryMirror.init(states, new PackedBlockState(Reflections.instance$Blocks$STONE$defaultState, BlockStateUtils.blockStateToId(Reflections.instance$Blocks$STONE$defaultState))); } private void registerEmptyBlock() { @@ -460,36 +458,8 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - Object eventsObj = ResourceConfigUtils.get(section, "events"); - EnumMap>> events = new EnumMap<>(EventTrigger.class); - if (eventsObj instanceof Map eventsSection) { - Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); - for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { - try { - EventTrigger eventTrigger = EventTrigger.valueOf(eventEntry.getKey().toUpperCase(Locale.ENGLISH)); - if (eventEntry.getValue() instanceof List list) { - if (list.size() == 1) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); - } else if (list.size() == 2) { - events.put(eventTrigger, List.of( - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) - )); - } else { - List> eventsList = new ArrayList<>(); - for (Object event : list) { - eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); - } - events.put(eventTrigger, eventsList); - } - } else if (eventEntry.getValue() instanceof Map eventSection) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); - } - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); - } - } - } + Object eventsObj = ResourceConfigUtils.get(section, "events", "event"); + EnumMap>> events = parseEvents(eventsObj); Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) @@ -543,6 +513,55 @@ public class BukkitBlockManager extends AbstractBlockManager { } } + private EnumMap>> parseEvents(Object eventsObj) { + EnumMap>> events = new EnumMap<>(EventTrigger.class); + if (eventsObj instanceof Map eventsSection) { + Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); + for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { + try { + EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); + if (eventEntry.getValue() instanceof List list) { + if (list.size() == 1) { + events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); + } else if (list.size() == 2) { + events.put(eventTrigger, List.of( + BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), + BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) + )); + } else { + List> eventsList = new ArrayList<>(); + for (Object event : list) { + eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); + } + events.put(eventTrigger, eventsList); + } + } else if (eventEntry.getValue() instanceof Map eventSection) { + events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); + } + } + } else if (eventsObj instanceof List list) { + @SuppressWarnings("unchecked") + List> eventsList = (List>) list; + for (Map eventSection : eventsList) { + Object onObj = eventSection.get("on"); + if (onObj == null) { + throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); + } + try { + EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); + Function function = BlockEventFunctions.fromMap(eventSection); + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); + } + } + } + return events; + } + private Map> parseProperties(Map propertiesSection) { Map> properties = new HashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 732978b30..d1e6b038e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -89,7 +89,7 @@ public class AxeItemBehavior extends ItemBehavior { bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1); // resend swing if it's not interactable on client side - if (!InteractUtils.isInteractable(BlockStateUtils.getBlockOwnerIdFromState(state.vanillaBlockState().handle()), + if (!InteractUtils.isInteractable( bukkitPlayer, BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), item ) || player.isSecondaryUseActive()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 847935ca0..39d62f1e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.bukkit.item.behavior; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.api.event.CustomBlockAttemptPlaceEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; @@ -21,6 +23,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.BlockPos; @@ -38,7 +41,6 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; -import javax.annotation.Nullable; import java.nio.file.Path; import java.util.Map; import java.util.Optional; @@ -57,34 +59,32 @@ public class BlockItemBehavior extends ItemBehavior { } public InteractionResult place(BlockPlaceContext context) { - if (!context.canPlace()) { - return InteractionResult.FAIL; - } Optional optionalBlock = BukkitBlockManager.instance().blockById(this.blockId); if (optionalBlock.isEmpty()) { CraftEngine.instance().logger().warn("Failed to place unknown block " + this.blockId); return InteractionResult.FAIL; } - CustomBlock block = optionalBlock.get(); - BlockPlaceContext placeContext = updatePlacementContext(context); - if (placeContext == null) { + if (!context.canPlace()) { return InteractionResult.FAIL; } - ImmutableBlockState blockStateToPlace = getPlacementState(placeContext, block); + + CustomBlock block = optionalBlock.get(); + BlockPos pos = context.getClickedPos(); + int maxY = context.getLevel().worldHeight().getMaxBuildHeight() - 1; + if (context.getClickedFace() == Direction.UP && pos.y() >= maxY) { + context.getPlayer().sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED)); + return InteractionResult.FAIL; + } + + ImmutableBlockState blockStateToPlace = getPlacementState(context, block); if (blockStateToPlace == null) { return InteractionResult.FAIL; } - Player player = placeContext.getPlayer(); - BlockPos pos = placeContext.getClickedPos(); - BlockPos againstPos = placeContext.getAgainstPos(); - World world = (World) placeContext.getLevel().platformWorld(); + + Player player = context.getPlayer(); + BlockPos againstPos = context.getAgainstPos(); + World world = (World) context.getLevel().platformWorld(); Location placeLocation = new Location(world, pos.x(), pos.y(), pos.z()); - - int gameTicks = player.gameTicks(); - if (!player.updateLastSuccessfulInteractionTick(gameTicks)) { - return InteractionResult.FAIL; - } - Block bukkitBlock = world.getBlockAt(placeLocation); Block againstBlock = world.getBlockAt(againstPos.x(), againstPos.y(), againstPos.z()); org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.platformPlayer(); @@ -105,6 +105,11 @@ public class BlockItemBehavior extends ItemBehavior { } } + int gameTicks = player.gameTicks(); + if (!player.updateLastSuccessfulInteractionTick(gameTicks)) { + return InteractionResult.FAIL; + } + // trigger event CustomBlockAttemptPlaceEvent attemptPlaceEvent = new CustomBlockAttemptPlaceEvent(bukkitPlayer, placeLocation.clone(), blockStateToPlace, DirectionUtils.toBlockFace(context.getClickedFace()), bukkitBlock, context.getHand()); @@ -117,7 +122,7 @@ public class BlockItemBehavior extends ItemBehavior { // place custom block CraftEngineBlocks.place(placeLocation, blockStateToPlace, UpdateOption.UPDATE_ALL_IMMEDIATE, false); // call bukkit event - BlockPlaceEvent bukkitPlaceEvent = new BlockPlaceEvent(bukkitBlock, previousState, againstBlock, (ItemStack) placeContext.getItem().getItem(), bukkitPlayer, true, context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND); + BlockPlaceEvent bukkitPlaceEvent = new BlockPlaceEvent(bukkitBlock, previousState, againstBlock, (ItemStack) context.getItem().getItem(), bukkitPlayer, true, context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND); if (EventUtils.fireAndCheckCancel(bukkitPlaceEvent)) { // revert changes previousState.update(true, false); @@ -133,23 +138,17 @@ public class BlockItemBehavior extends ItemBehavior { } if (!player.isCreativeMode()) { - Item item = placeContext.getItem(); + Item item = context.getItem(); item.count(item.count() - 1); item.load(); } - player.swingHand(placeContext.getHand()); - placeContext.getLevel().playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), blockStateToPlace.sounds().placeSound()); + player.swingHand(context.getHand()); + context.getLevel().playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), blockStateToPlace.sounds().placeSound()); world.sendGameEvent(bukkitPlayer, GameEvent.BLOCK_PLACE, new Vector(pos.x(), pos.y(), pos.z())); return InteractionResult.SUCCESS; } - // for child class to override - @Nullable - public BlockPlaceContext updatePlacementContext(BlockPlaceContext context) { - return context; - } - protected ImmutableBlockState getPlacementState(BlockPlaceContext context, CustomBlock block) { ImmutableBlockState state = block.getStateForPlacement(context); return state != null && this.canPlace(context, state) ? state : null; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 0dd515534..8606b48a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -54,6 +54,7 @@ public abstract class BukkitItemFactory> extend @Override protected boolean isBlockItem(W item) { + // todo 这个 isBlockItem 他考虑组件了吗??? return item.getItem().getType().isBlock(); } 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 31e379b78..225c4187b 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 @@ -1,13 +1,12 @@ package net.momirealms.craftengine.bukkit.item.listener; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionResult; @@ -15,6 +14,11 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.util.ClickType; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -24,7 +28,6 @@ import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; -import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -44,37 +47,139 @@ public class ItemEventListener implements Listener { this.plugin = plugin; } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onInteractBlock(PlayerInteractEvent event) { Action action = event.getAction(); - if (action != Action.LEFT_CLICK_BLOCK && action != Action.RIGHT_CLICK_BLOCK) { + Player player = event.getPlayer(); + if ( + (action != Action.LEFT_CLICK_BLOCK && action != Action.RIGHT_CLICK_BLOCK) || /* block is required */ + (player.getGameMode() == GameMode.SPECTATOR) || /* no spectator interactions */ + (action == Action.LEFT_CLICK_BLOCK && player.getGameMode() == GameMode.CREATIVE) /* it's breaking the block */ + ) { return; } + + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + // 如果本tick内主手已被处理,则不处理副手 + // 这是因为客户端可能会同时发主副手交互包,但实际上只能处理其中一个 + if (this.cancelEventIfHasInteraction(event, serverPlayer, hand)) { + return; + } + + // some common data Block block = Objects.requireNonNull(event.getClickedBlock()); - Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); + BlockData blockData = block.getBlockData(); + Object blockState = BlockStateUtils.blockDataToBlockState(blockData); + ImmutableBlockState immutableBlockState = null; int stateId = BlockStateUtils.blockStateToId(blockState); - if (BlockStateUtils.isVanillaBlock(stateId)) { - return; + Item itemInHand = serverPlayer.getItemInHand(hand); + + Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); + boolean hasItem = itemInHand != null; + boolean hasCustomItem = optionalCustomItem.isPresent(); + + // 处理自定义方块 + if (!BlockStateUtils.isVanillaBlock(stateId)) { + immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + // call the event if it's custom + CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent( + player, + block.getLocation(), + event.getInteractionPoint(), + immutableBlockState, + block, + event.getBlockFace(), + hand, + action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK, + event.getItem() + ); + if (EventUtils.fireAndCheckCancel(interactEvent)) { + event.setCancelled(true); + return; + } + // run custom functions + CustomBlock customBlock = immutableBlockState.owner().value(); + PlayerBlockActionContext context = PlayerBlockActionContext.of(serverPlayer, new BukkitBlockInWorld(block), ContextHolder.builder() + .withParameter(CommonParameters.BLOCK_STATE, immutableBlockState) + .withParameter(CommonParameters.PLAYER, serverPlayer) + .withParameter(CommonParameters.WORLD, serverPlayer.world()) + .withParameter(CommonParameters.LOCATION, new Vec3d(block.getX(), block.getY(), block.getZ())) + .withParameter(CommonParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT) + .build()); + customBlock.execute(context, EventTrigger.CLICK); + if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); + else customBlock.execute(context, EventTrigger.LEFT_CLICK); } - // it's breaking the block - if (action == Action.LEFT_CLICK_BLOCK && event.getPlayer().getGameMode() == GameMode.CREATIVE) { - return; - } + // interact block with items + if (hasItem && action == Action.RIGHT_CLICK_BLOCK) { + Location interactionPoint = Objects.requireNonNull(event.getInteractionPoint(), "interaction point should not be null"); + Direction direction = DirectionUtils.toDirection(event.getBlockFace()); + BlockPos pos = LocationUtils.toBlockPos(block.getLocation()); + Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); + BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false); - CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent( - event.getPlayer(), - block.getLocation(), - event.getInteractionPoint(), - BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId), - block, - event.getBlockFace(), - event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND, - action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK, - event.getItem() - ); - if (EventUtils.fireAndCheckCancel(interactEvent)) { - event.setCancelled(true); + // handle block item + if (itemInHand.isBlockItem()) { + // vanilla item + if (!hasCustomItem) { + // interact a custom block + if (immutableBlockState != null) { + // client won't have sounds if the clientside block is interactable + // so we should check and resend sounds on BlockPlaceEvent + BlockData craftBlockData = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()); + if (InteractUtils.isInteractable(player, craftBlockData, hitResult, itemInHand)) { + if (!serverPlayer.isSecondaryUseActive()) { + serverPlayer.setResendSound(); + } + } else { + if (BlockStateUtils.isReplaceable(immutableBlockState.customBlockState().handle()) && !BlockStateUtils.isReplaceable(immutableBlockState.vanillaBlockState().handle())) { + serverPlayer.setResendSwing(); + } + } + } + } + // custom item + else { + if (optionalCustomItem.get().settings().canPlaceRelatedVanillaBlock()) { + // 如果用户设置了允许放置对应的原版方块,那么直接返回。 + // 这种情况下最好是return,以避免同时触发多个behavior发生冲突 + // 当用户选择其作为原版方块放下时,自定义行为可能已经不重要了? + return; + } else { + // todo 实际上这里的处理并不正确,因为判断玩家是否能够放置那个方块需要更加细节的判断。比如玩家无法对着树叶放置火把,但是交互事件依然触发,此情况下不可丢弃自定义行为。 + if (serverPlayer.isSecondaryUseActive() || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) { + event.setCancelled(true); + } + } + } + } + + // 检查其他的物品行为,物品行为理论只在交互时处理 + Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); + // 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为 + if (optionalItemBehaviors.isPresent()) { + // 检测是否可交互应当只判断原版方块,因为自定义方块早就判断过了,如果可交互不可能到这一步 + boolean interactable = immutableBlockState == null && InteractUtils.isInteractable(player, blockData, hitResult, itemInHand); + // 如果方块可交互但是玩家没shift,那么原版的方块交互优先,取消自定义物品的behavior + // todo 如果我的物品行为允许某些交互呢?是否值得进一步处理? + if (!serverPlayer.isSecondaryUseActive() && interactable) { + return; + } + // 依次执行物品行为 + for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { + InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(serverPlayer, hand, hitResult)); + if (result == InteractionResult.SUCCESS_AND_CANCEL) { + event.setCancelled(true); + return; + } + // 非pass的情况直接结束 + if (result != InteractionResult.PASS) { + return; + } + } + } } } @@ -112,116 +217,6 @@ public class ItemEventListener implements Listener { } } - @EventHandler(priority = EventPriority.HIGHEST) - public void onInteractAtBlock(PlayerInteractEvent event) { - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - if (event.useItemInHand() == Event.Result.DENY || event.useInteractedBlock() == Event.Result.DENY) return; - Location interactionPoint = event.getInteractionPoint(); - if (interactionPoint == null) return; - Player bukkitPlayer = event.getPlayer(); - Block clickedBlock = Objects.requireNonNull(event.getClickedBlock()); - BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer); - InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - // 如果同一tick已经处理过交互,则忽略 - if (cancelEventIfHasInteraction(event, player, hand)) { - return; - } - - // Gets the item in hand - Item itemInHand = player.getItemInHand(hand); - if (itemInHand == null) return; - Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); - - // has custom item behavior - // 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为 - if (optionalItemBehaviors.isPresent()) { - BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation()); - Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); - Direction direction = DirectionUtils.toDirection(event.getBlockFace()); - BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false); - boolean interactable = InteractUtils.isInteractable(BlockStateUtils.getBlockOwnerId(clickedBlock), bukkitPlayer, clickedBlock.getBlockData(), hitResult, itemInHand); - - // do not allow to place block if it's a vanilla block - // 如果这个是自定义物品,那么会阻止玩家放置其对应的原版方块 - Optional> optionalCustomItem = itemInHand.getCustomItem(); - if (itemInHand.isBlockItem() && optionalCustomItem.isPresent()) { - // it's a custom item, but now it's ignored - // 如果用户设置了允许放置对应的原版方块,那么直接返回。 - // todo 实际上这里的处理并不正确,因为判断玩家是否能够放置那个方块需要更加细节的判断。比如玩家无法对着树叶放置火把,但是交互事件依然触发,此情况下不可丢弃自定义行为。 - if (optionalCustomItem.get().settings().canPlaceRelatedVanillaBlock()) { - return; - } - // 如果玩家潜行放置或者交互对象不可交互,那么取消掉事件以防止玩家放置。 - // todo 这些处理应该要搬到BlockPlaceEvent? - if (!interactable || player.isSecondaryUseActive()) { - event.setCancelled(true); - } - } - - if (!player.isSecondaryUseActive() && interactable) { - // if it's interactable on server, cancel the custom behaviors - return; - } - - // no spectator interactions - if (player.isSpectatorMode()) { - return; - } - - for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { - InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult)); - if (result == InteractionResult.SUCCESS_AND_CANCEL) { - event.setCancelled(true); - return; - } - int maxY = player.world().worldHeight().getMaxBuildHeight() - 1; - if (direction == Direction.UP - && result != InteractionResult.SUCCESS - && pos.y() >= maxY - && itemBehavior instanceof BlockItemBehavior - ) { - player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED)); - return; - } - if (result != InteractionResult.PASS) { - return; - } - } - } - - // it's a vanilla block - // 这部分代码是处理放置原版方块“缺失的”声音和挥手动画 - if (itemInHand.isBlockItem() && !itemInHand.isCustomItem()) { - // client won't have sounds if the fake block is interactable - // so we should check and resend sounds on interact - Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData()); - int stateId = BlockStateUtils.blockStateToId(blockState); - ImmutableBlockState againstCustomBlock = BukkitBlockManager.instance().getImmutableBlockState(stateId); - if (againstCustomBlock == null || againstCustomBlock.isEmpty()) { - return; - } - - BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation()); - Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); - Direction direction = DirectionUtils.toDirection(event.getBlockFace()); - BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false); - try { - BlockData craftBlockData = BlockStateUtils.fromBlockData(againstCustomBlock.vanillaBlockState().handle()); - if (InteractUtils.isInteractable(KeyUtils.namespacedKey2Key(craftBlockData.getMaterial().getKey()), bukkitPlayer, craftBlockData, hitResult, itemInHand)) { - if (!player.isSecondaryUseActive()) { - player.setResendSound(); - } - } else { - if (BlockStateUtils.isReplaceable(againstCustomBlock.customBlockState().handle()) && !BlockStateUtils.isReplaceable(againstCustomBlock.vanillaBlockState().handle())) { - player.setResendSwing(); - } - } - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get CraftBlockData", e); - } - } - } - private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { if (hand == InteractionHand.OFF_HAND) { int currentTicks = player.gameTicks(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 69bcf57e2..ab1b59966 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.util.BlockTags; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Material; 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 515fdfc63..81163c601 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 @@ -101,8 +101,11 @@ public class BlockStateUtils { } public static Key getBlockOwnerId(Block block) { - BlockData data = block.getBlockData(); - Object blockState = blockDataToBlockState(data); + return getBlockOwnerId(block.getBlockData()); + } + + public static Key getBlockOwnerId(BlockData block) { + Object blockState = blockDataToBlockState(block); return getBlockOwnerIdFromState(blockState); } @@ -188,8 +191,12 @@ public class BlockStateUtils { Reflections.field$BlockStateBase$replaceable.set(state, replaceable); } - public static boolean isReplaceable(Object state) throws ReflectiveOperationException { - return (boolean) Reflections.field$BlockStateBase$replaceable.get(state); + public static boolean isReplaceable(Object state) { + try { + return (boolean) Reflections.field$BlockStateBase$replaceable.get(state); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to get replaceable property", e); + } } public static void setCanOcclude(Object state, boolean canOcclude) throws ReflectiveOperationException { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index ac0bf989c..7152b3f98 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -273,9 +273,10 @@ public class InteractUtils { } } - public static boolean isInteractable(Key block, org.bukkit.entity.Player player, BlockData state, BlockHitResult hit, Item item) { - if (INTERACTIONS.containsKey(block)) { - return INTERACTIONS.get(block).apply(player, item, state, hit); + public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, Item item) { + Key blockType = BlockStateUtils.getBlockOwnerId(state); + if (INTERACTIONS.containsKey(blockType)) { + return INTERACTIONS.get(blockType).apply(player, item, state, hit); } else { return false; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java index e54f30677..28e6e971e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java @@ -5,7 +5,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.util.FriendlyByteBuf; -import net.momirealms.craftengine.core.util.Key; import java.util.ArrayList; import java.util.HashMap; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java index 77645ffa1..f93bf3a57 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java @@ -2,13 +2,15 @@ package net.momirealms.craftengine.core.block; public class BlockRegistryMirror { private static PackedBlockState[] customBlockStates; + private static PackedBlockState stoneState; - public static void init(PackedBlockState[] states) { + public static void init(PackedBlockState[] states, PackedBlockState state) { customBlockStates = states; + stoneState = state; } public static PackedBlockState stateByRegistryId(int vanillaId) { - if (vanillaId < 0) return null; + if (vanillaId < 0) return stoneState; return customBlockStates[vanillaId]; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index b30236ae6..6ce564f82 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -93,6 +93,12 @@ public abstract class CustomBlock { return lootTable; } + public void execute(PlayerBlockActionContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + @NotNull public BlockStateVariantProvider variantProvider() { return variantProvider; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 7e53699aa..30be17f0c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -20,9 +20,7 @@ import java.util.List; public class ImmutableBlockState extends BlockStateHolder { private CompoundTag tag; - @Nullable private PackedBlockState customBlockState; - @Nullable private PackedBlockState vanillaBlockState; private BlockBehavior behavior; @@ -84,18 +82,18 @@ public class ImmutableBlockState extends BlockStateHolder { } public PackedBlockState customBlockState() { - return customBlockState; + return this.customBlockState; } public PackedBlockState vanillaBlockState() { - return vanillaBlockState; + return this.vanillaBlockState; } - public void setCustomBlockState(@Nullable PackedBlockState customBlockState) { + public void setCustomBlockState(@NotNull PackedBlockState customBlockState) { this.customBlockState = customBlockState; } - public void setVanillaBlockState(@Nullable PackedBlockState vanillaBlockState) { + public void setVanillaBlockState(@NotNull PackedBlockState vanillaBlockState) { this.vanillaBlockState = vanillaBlockState; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java index c7251cd9e..5e3c9092d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.loot; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.world.World; @@ -12,7 +11,6 @@ import javax.annotation.Nullable; public class LootContext extends PlayerOptionalContext { private final World world; private final float luck; - private Item tempLoot; public LootContext(@NotNull World world, @Nullable Player player, float luck, @NotNull ContextHolder contexts) { super(player, contexts); @@ -27,12 +25,4 @@ public class LootContext extends PlayerOptionalContext { public World world() { return this.world; } - - public Item tempLoot() { - return this.tempLoot; - } - - public void setTempLoot(Item tempLoot) { - this.tempLoot = tempLoot; - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java new file mode 100644 index 000000000..ce9d60570 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java @@ -0,0 +1,44 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class ClickTypeCondition implements Condition { + private final ClickType clickType; + + public ClickTypeCondition(ClickType clickType) { + this.clickType = clickType; + } + + @Override + public Key type() { + return CommonConditions.CLICK_TYPE; + } + + @Override + public boolean test(CTX ctx) { + Optional clickTypeOptional = ctx.getOptionalParameter(CommonParameters.CLICK_TYPE); + if (clickTypeOptional.isPresent()) { + ClickType clickType = clickTypeOptional.get(); + return clickType.equals(this.clickType); + } + return false; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + ClickType clickType = ClickType.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("click-type"), "warning.config.condition.click_type.missing_click_type").toUpperCase(Locale.ENGLISH)); + return new ClickTypeCondition<>(clickType); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 1607f8013..59cc4895d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -10,6 +10,7 @@ public final class CommonConditions { public static final Key ANY_OF = Key.of("craftengine:any_of"); public static final Key INVERTED = Key.of("craftengine:inverted"); public static final Key MATCH_ITEM = Key.of("craftengine:match_item"); + public static final Key CLICK_TYPE = Key.of("craftengine:click_type"); public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java index 25d56a813..7d079994a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; @@ -11,7 +10,6 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -// TODO 将loot functions迁移过来 public abstract class AbstractConditionalFunction implements Function { protected final List> predicates; private final Predicate compositePredicates; @@ -30,7 +28,7 @@ public abstract class AbstractConditionalFunction implement protected abstract void runInternal(CTX ctx); - public static abstract class AbstractFactory implements Factory> { + public static abstract class AbstractFactory implements FunctionFactory { private final java.util.function.Function, Condition> factory; public AbstractFactory(java.util.function.Function, Condition> factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/FunctionFactory.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/FunctionFactory.java new file mode 100644 index 000000000..f4e52f07c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/FunctionFactory.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Context; + +import java.util.Map; + +public interface FunctionFactory { + + Function create(Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java index 21c2ccabf..6428df308 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java @@ -6,7 +6,6 @@ import com.ezylang.evalex.parser.ParseException; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -41,7 +40,7 @@ public class ExpressionNumberProvider implements NumberProvider { return this.expr; } - public static class FactoryImpl implements Factory { + public static class FactoryImpl implements NumberProviderFactory { @Override public NumberProvider create(Map arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java index cfbd165f9..3bbf7729f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.context.number; import com.ezylang.evalex.Expression; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -27,7 +26,7 @@ public class FixedNumberProvider implements NumberProvider { return NumberProviders.FIXED; } - public static class FactoryImpl implements Factory { + public static class FactoryImpl implements NumberProviderFactory { @Override public NumberProvider create(Map arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviderFactory.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviderFactory.java new file mode 100644 index 000000000..3d557362a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviderFactory.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import java.util.Map; + +public interface NumberProviderFactory { + + NumberProvider create(Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java index 5d5d609a4..8baef2d0b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; @@ -27,8 +26,8 @@ public class NumberProviders { register(EXPRESSION, ExpressionNumberProvider.FACTORY); } - public static void register(Key key, Factory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) + public static void register(Key key, NumberProviderFactory factory) { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) .registerForHolder(new ResourceKey<>(Registries.NUMBER_PROVIDER_FACTORY.location(), key)); holder.bindValue(factory); } @@ -45,7 +44,7 @@ public class NumberProviders { public static NumberProvider fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.number.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - Factory factory = BuiltInRegistries.NUMBER_PROVIDER_FACTORY.getValue(key); + NumberProviderFactory factory = BuiltInRegistries.NUMBER_PROVIDER_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.number.invalid_type", type); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java index 38cbf80ae..62d7c4ddc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.context.number; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -41,7 +40,7 @@ public class UniformNumberProvider implements NumberProvider { return NumberProviders.UNIFORM; } - public static class FactoryImpl implements Factory { + public static class FactoryImpl implements NumberProviderFactory { @Override public NumberProvider create(Map arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java index 615aa93bb..2b2ad13c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.ClickType; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; @@ -18,5 +19,6 @@ public final class CommonParameters { public static final ContextKey FALLING_BLOCK = ContextKey.of("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.of("explosion_radius"); public static final ContextKey PLAYER = ContextKey.of("player"); + public static final ContextKey CLICK_TYPE = ContextKey.of("click_type"); public static final ContextKey BLOCK_STATE = ContextKey.of("block_state"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java index ae5010c81..7008839c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java @@ -3,6 +3,8 @@ package net.momirealms.craftengine.core.plugin.context.selector; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.Key; +import java.util.Map; + public class PlayerSelectors { public static final Key ALL = Key.of("craftengine:all"); public static final Key SELF = Key.of("craftengine:self"); @@ -15,6 +17,7 @@ public class PlayerSelectors { } else if (string.equals("all") || string.equals("@all") || string.equals("@a")) { return new AllPlayerSelector<>(); } + } else if (object instanceof Map map) { } throw new UnsupportedOperationException("Not supported yet."); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java index 5cb58ed8a..6acee5ff4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java @@ -2,28 +2,52 @@ package net.momirealms.craftengine.core.plugin.event; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; -import net.momirealms.craftengine.core.plugin.context.condition.InvertedCondition; +import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Map; public class BlockEventConditions { + static { + register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>()); + register(CommonConditions.MATCH_BLOCK_PROPERTY, new MatchBlockPropertyCondition.FactoryImpl<>()); + register(CommonConditions.TABLE_BONUS, new TableBonusCondition.FactoryImpl<>()); + register(CommonConditions.SURVIVES_EXPLOSION, new SurvivesExplosionCondition.FactoryImpl<>()); + register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.ENCHANTMENT, new EnchantmentCondition.FactoryImpl<>()); + register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); + register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); + register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); + register(CommonConditions.CLICK_TYPE, new ClickTypeCondition.FactoryImpl<>()); + } + + public static void register(Key key, ConditionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_CONDITION_FACTORY.location(), key)); + holder.bindValue(factory); + } + public static Condition fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.event.condition.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); if (key.value().charAt(0) == '!') { - Factory> factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); } return new InvertedCondition<>(factory.create(map)); } else { - Factory> factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); + ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java index 885e7fec2..0cce7cdf1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java @@ -4,12 +4,12 @@ import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Factory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; @@ -22,8 +22,8 @@ public class BlockEventFunctions { register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(BlockEventConditions::fromMap)); } - public static void register(Key key, Factory> factory) { - Holder.Reference>> holder = ((WritableRegistry>>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) + public static void register(Key key, FunctionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_FUNCTION_FACTORY.location(), key)); holder.bindValue(factory); } @@ -31,7 +31,7 @@ public class BlockEventFunctions { public static Function fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "TODO I18N"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - Factory> factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); + FunctionFactory factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("TODO I18N", type); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java index 5d26f6c1f..7e9ef2820 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -1,8 +1,36 @@ package net.momirealms.craftengine.core.plugin.event; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + public enum EventTrigger { - USE_ITEM, - USE_ITEM_ON, - CONSUME, - BREAK + CLICK("click", "interact"), + LEFT_CLICK("attack", "left_click"), + RIGHT_CLICK("right_click", "use_on", "use", "use_item_on"), + CONSUME("eat", "consume", "drink"), + BREAK("break", "dig"),; + + public static final Map BY_NAME = new HashMap<>(); + private final String[] names; + + EventTrigger(String... names) { + this.names = names; + } + + public String[] names() { + return names; + } + + static { + for (EventTrigger trigger : EventTrigger.values()) { + for (String name : trigger.names()) { + BY_NAME.put(name, trigger); + } + } + } + + public static EventTrigger byName(String name) { + return Optional.ofNullable(BY_NAME.get(name)).orElseThrow(() -> new IllegalArgumentException("Unknown event trigger: " + name)); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index a92d3db1d..63e13ac40 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -21,12 +21,10 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; -import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; -import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; @@ -39,7 +37,7 @@ public class BuiltInRegistries { public static final Registry> LOOT_FUNCTION_FACTORY = createRegistry(Registries.LOOT_FUNCTION_FACTORY); public static final Registry> LOOT_CONDITION_FACTORY = createRegistry(Registries.LOOT_CONDITION_FACTORY); public static final Registry> LOOT_ENTRY_CONTAINER_FACTORY = createRegistry(Registries.LOOT_ENTRY_CONTAINER_FACTORY); - public static final Registry> NUMBER_PROVIDER_FACTORY = createRegistry(Registries.NUMBER_PROVIDER_FACTORY); + public static final Registry NUMBER_PROVIDER_FACTORY = createRegistry(Registries.NUMBER_PROVIDER_FACTORY); public static final Registry TEMPLATE_ARGUMENT_FACTORY = createRegistry(Registries.TEMPLATE_ARGUMENT_FACTORY); public static final Registry ITEM_MODEL_FACTORY = createRegistry(Registries.ITEM_MODEL_FACTORY); public static final Registry TINT_FACTORY = createRegistry(Registries.TINT_FACTORY); @@ -54,8 +52,8 @@ public class BuiltInRegistries { public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); - public static final Registry>> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); - public static final Registry>> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); + public static final Registry> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); + public static final Registry> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 434302ba9..a5bd19c5d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -21,12 +21,10 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; -import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; -import net.momirealms.craftengine.core.util.Factory; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; @@ -40,7 +38,7 @@ public class Registries { public static final ResourceKey>> LOOT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_function_factory")); public static final ResourceKey>> LOOT_ENTRY_CONTAINER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_entry_container_factory")); public static final ResourceKey>> LOOT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_condition_factory")); - public static final ResourceKey>> NUMBER_PROVIDER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); + public static final ResourceKey> NUMBER_PROVIDER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); public static final ResourceKey> TEMPLATE_ARGUMENT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("template_argument_factory")); public static final ResourceKey> ITEM_MODEL_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_factory")); public static final ResourceKey> TINT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("tint_factory")); @@ -55,6 +53,6 @@ public class Registries { public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); - public static final ResourceKey>>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); + public static final ResourceKey>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); + public static final ResourceKey>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ClickType.java b/core/src/main/java/net/momirealms/craftengine/core/util/ClickType.java new file mode 100644 index 000000000..1489885b7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ClickType.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.util; + +public enum ClickType { + LEFT, RIGHT, MIDDLE +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java b/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java deleted file mode 100644 index ec3e37b2f..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Factory.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import java.util.Map; - -public interface Factory { - - T create(Map args); -} diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 09f390769..52214c52a 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -18,15 +18,15 @@ import net.momirealms.craftengine.mod.CraftEnginePlugin; import net.momirealms.craftengine.mod.util.NoteBlockUtils; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; @SuppressWarnings("deprecation") -public class CraftEngineBlock - extends Block - implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock - //TODO , SimpleWaterloggedBlock -{ +public class CraftEngineBlock extends Block + implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState()); + private static final Logger LOGGER = LogManager.getLogger(CraftEngineBlock.class); private boolean isNoteBlock; public ObjectHolder behaviorHolder; public ObjectHolder shapeHolder; @@ -39,30 +39,30 @@ public class CraftEngineBlock } public void setNoteBlock(boolean noteBlock) { - isNoteBlock = noteBlock; + this.isNoteBlock = noteBlock; } @Override public ObjectHolder getBehaviorHolder() { - return behaviorHolder; + return this.behaviorHolder; } @Override public ObjectHolder getShapeHolder() { - return shapeHolder; + return this.shapeHolder; } @Override public boolean isNoteBlock() { - return isClientSideNoteBlock; + return this.isClientSideNoteBlock; } @Override public @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { try { - return (VoxelShape) shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); + return (VoxelShape) this.shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.getShape(state, level, pos, context); } } @@ -72,7 +72,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().rotate(this, new Object[]{state, rotation}, () -> super.rotate(state, rotation)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.rotate(state, rotation); } } @@ -82,7 +82,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().mirror(this, new Object[]{state, mirror}, () -> super.mirror(state, mirror)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.mirror(state, mirror); } } @@ -95,7 +95,7 @@ public class CraftEngineBlock return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.tick(state, level, pos, random); } } @@ -103,12 +103,12 @@ public class CraftEngineBlock @Override public void randomTick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) { try { - behaviorHolder.value().randomTick(this, new Object[]{state, level, pos, random}, () -> { + this.behaviorHolder.value().randomTick(this, new Object[]{state, level, pos, random}, () -> { super.randomTick(state, level, pos, random); return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.randomTick(state, level, pos, random); } } @@ -116,12 +116,12 @@ public class CraftEngineBlock @Override public void onPlace(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState oldState, boolean movedByPiston) { try { - behaviorHolder.value().onPlace(this, new Object[]{state, level, pos, oldState, movedByPiston}, () -> { + this.behaviorHolder.value().onPlace(this, new Object[]{state, level, pos, oldState, movedByPiston}, () -> { super.onPlace(state, level, pos, oldState, movedByPiston); return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.onPlace(state, level, pos, oldState, movedByPiston); } } @@ -129,9 +129,9 @@ public class CraftEngineBlock @Override public void onBrokenAfterFall(@NotNull Level level, @NotNull BlockPos pos, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); + this.behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); Fallable.super.onBrokenAfterFall(level, pos, fallingBlock); } } @@ -139,27 +139,27 @@ public class CraftEngineBlock @Override public boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) { try { - return behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); + return this.behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.canSurvive(state, level, pos); } } @Override - public BlockState updateShape(@NotNull BlockState state, - @NotNull Direction direction, - @NotNull BlockState neighborState, - @NotNull LevelAccessor world, - @NotNull BlockPos pos, - @NotNull BlockPos neighborPos) { + public @NotNull BlockState updateShape(@NotNull BlockState state, + @NotNull Direction direction, + @NotNull BlockState neighborState, + @NotNull LevelAccessor world, + @NotNull BlockPos pos, + @NotNull BlockPos neighborPos) { try { - if (isNoteBlock && world instanceof ServerLevel serverLevel) { + if (this.isNoteBlock && world instanceof ServerLevel serverLevel) { startNoteBlockChain(direction, serverLevel, pos); } - return (BlockState) behaviorHolder.value().updateShape(this, new Object[]{state, direction, neighborState, world, pos, neighborPos}, () -> super.updateShape(state, direction, neighborState, world, pos, neighborPos)); + return (BlockState) this.behaviorHolder.value().updateShape(this, new Object[]{state, direction, neighborState, world, pos, neighborPos}, () -> super.updateShape(state, direction, neighborState, world, pos, neighborPos)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.updateShape(state, direction, neighborState, world, pos, neighborPos); } } @@ -191,9 +191,9 @@ public class CraftEngineBlock @Override public boolean isValidBonemealTarget(@NotNull LevelReader world, @NotNull BlockPos pos, @NotNull BlockState state, boolean isClient) { try { - return behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{world, pos, state, isClient}); + return this.behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{world, pos, state, isClient}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -203,7 +203,7 @@ public class CraftEngineBlock try { return behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -211,49 +211,18 @@ public class CraftEngineBlock @Override public void performBonemeal(@NotNull ServerLevel serverLevel, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); + this.behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } @Override public void onLand(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull BlockState replaceableState, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); + this.behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } - -// @Override -// public boolean canPlaceLiquid(@Nullable Player player, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Fluid fluid) { -// try { -// return behaviorHolder.value().canPlaceLiquid(this, new Object[]{player, level, pos, state, fluid}, () -> SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid); -// } -// } -// -// @Override -// public boolean placeLiquid(@NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull FluidState fluidState) { -// try { -// return behaviorHolder.value().placeLiquid(this, new Object[]{level, pos, state, fluidState}, () -> SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState); -// } -// } -// -// @NotNull -// @Override -// public ItemStack pickupBlock(@Nullable Player player, @NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state) { -// try { -// return (ItemStack) behaviorHolder.value().pickupBlock(this, new Object[]{player, level, pos, state}, () -> SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state); -// } -// } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 8b3039c7b..4e37a60ef 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -18,14 +18,14 @@ import net.momirealms.craftengine.mod.CraftEnginePlugin; import net.momirealms.craftengine.mod.util.NoteBlockUtils; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; -public class CraftEngineBlock - extends Block - implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock - //TODO , SimpleWaterloggedBlock -{ +public class CraftEngineBlock extends Block + implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState()); + private static final Logger LOGGER = LogManager.getLogger(CraftEngineBlock.class); private boolean isNoteBlock; public ObjectHolder behaviorHolder; public ObjectHolder shapeHolder; @@ -38,30 +38,30 @@ public class CraftEngineBlock } public void setNoteBlock(boolean noteBlock) { - isNoteBlock = noteBlock; + this.isNoteBlock = noteBlock; } @Override public ObjectHolder getBehaviorHolder() { - return behaviorHolder; + return this.behaviorHolder; } @Override public ObjectHolder getShapeHolder() { - return shapeHolder; + return this.shapeHolder; } @Override public boolean isNoteBlock() { - return isClientSideNoteBlock; + return this.isClientSideNoteBlock; } @Override protected @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { try { - return (VoxelShape) shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); + return (VoxelShape) this.shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.getShape(state, level, pos, context); } } @@ -71,7 +71,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().rotate(this, new Object[]{state, rotation}, () -> super.rotate(state, rotation)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.rotate(state, rotation); } } @@ -81,7 +81,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().mirror(this, new Object[]{state, mirror}, () -> super.mirror(state, mirror)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.mirror(state, mirror); } } @@ -94,7 +94,7 @@ public class CraftEngineBlock return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.tick(state, level, pos, random); } } @@ -102,12 +102,12 @@ public class CraftEngineBlock @Override protected void randomTick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) { try { - behaviorHolder.value().randomTick(this, new Object[]{state, level, pos, random}, () -> { + this.behaviorHolder.value().randomTick(this, new Object[]{state, level, pos, random}, () -> { super.randomTick(state, level, pos, random); return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.randomTick(state, level, pos, random); } } @@ -115,12 +115,12 @@ public class CraftEngineBlock @Override protected void onPlace(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState oldState, boolean movedByPiston) { try { - behaviorHolder.value().onPlace(this, new Object[]{state, level, pos, oldState, movedByPiston}, () -> { + this.behaviorHolder.value().onPlace(this, new Object[]{state, level, pos, oldState, movedByPiston}, () -> { super.onPlace(state, level, pos, oldState, movedByPiston); return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.onPlace(state, level, pos, oldState, movedByPiston); } } @@ -128,9 +128,9 @@ public class CraftEngineBlock @Override public void onBrokenAfterFall(@NotNull Level level, @NotNull BlockPos pos, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); + this.behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); Fallable.super.onBrokenAfterFall(level, pos, fallingBlock); } } @@ -138,29 +138,29 @@ public class CraftEngineBlock @Override protected boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) { try { - return behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); + return this.behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.canSurvive(state, level, pos); } } @Override - protected BlockState updateShape(@NotNull BlockState state, - @NotNull LevelReader level, - @NotNull ScheduledTickAccess scheduledTickAccess, - @NotNull BlockPos pos, - @NotNull Direction direction, - @NotNull BlockPos neighborPos, - @NotNull BlockState neighborState, - @NotNull RandomSource random) { + protected @NotNull BlockState updateShape(@NotNull BlockState state, + @NotNull LevelReader level, + @NotNull ScheduledTickAccess scheduledTickAccess, + @NotNull BlockPos pos, + @NotNull Direction direction, + @NotNull BlockPos neighborPos, + @NotNull BlockState neighborState, + @NotNull RandomSource random) { try { - if (isNoteBlock && level instanceof ServerLevel serverLevel) { + if (this.isNoteBlock && level instanceof ServerLevel serverLevel) { startNoteBlockChain(direction, serverLevel, pos); } - return (BlockState) behaviorHolder.value().updateShape(this, new Object[]{state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random}, () -> super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random)); + return (BlockState) this.behaviorHolder.value().updateShape(this, new Object[]{state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random}, () -> super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); } } @@ -189,22 +189,12 @@ public class CraftEngineBlock } } -// @Override -// protected @NotNull FluidState getFluidState(@NotNull BlockState state) { -// try { -// return (FluidState) behaviorHolder.value().getFluidState(this, new Object[]{state}, () -> super.getFluidState(state)); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.getFluidState(state); -// } -// } - @Override public boolean isValidBonemealTarget(@NotNull LevelReader levelReader, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - return behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{levelReader, blockPos, blockState}); + return this.behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{levelReader, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -212,9 +202,9 @@ public class CraftEngineBlock @Override public boolean isBonemealSuccess(@NotNull Level level, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - return behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState}); + return this.behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -222,49 +212,18 @@ public class CraftEngineBlock @Override public void performBonemeal(@NotNull ServerLevel serverLevel, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); + this.behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } @Override public void onLand(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull BlockState replaceableState, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); + this.behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } - -// @Override -// public boolean canPlaceLiquid(@Nullable Player player, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull Fluid fluid) { -// try { -// return behaviorHolder.value().canPlaceLiquid(this, new Object[]{player, level, pos, state, fluid}, () -> SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.canPlaceLiquid(player, level, pos, state, fluid); -// } -// } -// -// @Override -// public boolean placeLiquid(@NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull FluidState fluidState) { -// try { -// return behaviorHolder.value().placeLiquid(this, new Object[]{level, pos, state, fluidState}, () -> SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.placeLiquid(level, pos, state, fluidState); -// } -// } -// -// @NotNull -// @Override -// public ItemStack pickupBlock(@Nullable Player player, @NotNull LevelAccessor level, @NotNull BlockPos pos, @NotNull BlockState state) { -// try { -// return (ItemStack) behaviorHolder.value().pickupBlock(this, new Object[]{player, level, pos, state}, () -> SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state)); -// } catch (Exception e) { -// e.printStackTrace(); -// return SimpleWaterloggedBlock.super.pickupBlock(player, level, pos, state); -// } -// } } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index cec744de3..212e34087 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -5,31 +5,27 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; import net.momirealms.craftengine.mod.util.NoteBlockUtils; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; -public class CraftEngineBlock - extends Block - implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock -{ +public class CraftEngineBlock extends Block + implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState()); + private static final Logger LOGGER = LogManager.getLogger(CraftEngineBlock.class); private boolean isNoteBlock; public ObjectHolder behaviorHolder; public ObjectHolder shapeHolder; @@ -42,30 +38,30 @@ public class CraftEngineBlock } public void setNoteBlock(boolean noteBlock) { - isNoteBlock = noteBlock; + this.isNoteBlock = noteBlock; } @Override public ObjectHolder getBehaviorHolder() { - return behaviorHolder; + return this.behaviorHolder; } @Override public ObjectHolder getShapeHolder() { - return shapeHolder; + return this.shapeHolder; } @Override public boolean isNoteBlock() { - return isClientSideNoteBlock; + return this.isClientSideNoteBlock; } @Override protected @NotNull VoxelShape getShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { try { - return (VoxelShape) shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); + return (VoxelShape) this.shapeHolder.value().getShape(this, new Object[]{state, level, pos, context}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.getShape(state, level, pos, context); } } @@ -75,7 +71,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().rotate(this, new Object[]{state, rotation}, () -> super.rotate(state, rotation)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.rotate(state, rotation); } } @@ -85,7 +81,7 @@ public class CraftEngineBlock try { return (BlockState) this.behaviorHolder.value().mirror(this, new Object[]{state, mirror}, () -> super.mirror(state, mirror)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.mirror(state, mirror); } } @@ -98,7 +94,7 @@ public class CraftEngineBlock return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.tick(state, level, pos, random); } } @@ -111,7 +107,7 @@ public class CraftEngineBlock return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.randomTick(state, level, pos, random); } } @@ -124,7 +120,7 @@ public class CraftEngineBlock return null; }); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); super.onPlace(state, level, pos, oldState, movedByPiston); } } @@ -132,9 +128,9 @@ public class CraftEngineBlock @Override public void onBrokenAfterFall(@NotNull Level level, @NotNull BlockPos pos, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); + this.behaviorHolder.value().onBrokenAfterFall(this, new Object[]{level, pos, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); Fallable.super.onBrokenAfterFall(level, pos, fallingBlock); } } @@ -142,9 +138,9 @@ public class CraftEngineBlock @Override protected boolean canSurvive(@NotNull BlockState state, @NotNull LevelReader level, @NotNull BlockPos pos) { try { - return behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); + return this.behaviorHolder.value().canSurvive(this, new Object[]{state, level, pos}, () -> super.canSurvive(state, level, pos)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.canSurvive(state, level, pos); } } @@ -159,12 +155,12 @@ public class CraftEngineBlock @NotNull BlockState neighborState, @NotNull RandomSource random) { try { - if (isNoteBlock && level instanceof ServerLevel serverLevel) { + if (this.isNoteBlock && level instanceof ServerLevel serverLevel) { startNoteBlockChain(direction, serverLevel, pos); } - return (BlockState) behaviorHolder.value().updateShape(this, new Object[]{state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random}, () -> super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random)); + return (BlockState) this.behaviorHolder.value().updateShape(this, new Object[]{state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random}, () -> super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random)); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); } } @@ -196,9 +192,9 @@ public class CraftEngineBlock @Override public boolean isValidBonemealTarget(@NotNull LevelReader levelReader, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - return behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{levelReader, blockPos, blockState}); + return this.behaviorHolder.value().isValidBoneMealTarget(this, new Object[]{levelReader, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -206,9 +202,9 @@ public class CraftEngineBlock @Override public boolean isBonemealSuccess(@NotNull Level level, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - return behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState}); + return this.behaviorHolder.value().isBoneMealSuccess(this, new Object[]{level, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); return false; } } @@ -216,38 +212,18 @@ public class CraftEngineBlock @Override public void performBonemeal(@NotNull ServerLevel serverLevel, @NotNull RandomSource randomSource, @NotNull BlockPos blockPos, @NotNull BlockState blockState) { try { - behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); + this.behaviorHolder.value().performBoneMeal(this, new Object[]{serverLevel, randomSource, blockPos, blockState}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } @Override public void onLand(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull BlockState replaceableState, @NotNull FallingBlockEntity fallingBlock) { try { - behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); + this.behaviorHolder.value().onLand(this, new Object[]{level, pos, state, replaceableState, fallingBlock}); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e); } } -// -// @Override -// protected @NotNull InteractionResult useWithoutItem(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull BlockHitResult hitResult) { -// try { -// return (InteractionResult) behaviorHolder.value().useWithoutItem(this, new Object[]{state, level, pos, player, hitResult}, () -> super.useWithoutItem(state, level, pos, player, hitResult)); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.useWithoutItem(state, level, pos, player, hitResult); -// } -// } -// -// @Override -// protected @NotNull InteractionResult useItemOn(@NotNull ItemStack stack, @NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) { -// try { -// return (InteractionResult) behaviorHolder.value().useItemOn(this, new Object[]{stack, stack, level, pos, player, hand, hitResult}, () -> super.useItemOn(stack, state, level, pos, player, hand, hitResult)); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.useItemOn(stack, state, level, pos, player, hand, hitResult); -// } -// } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index c48115996..24e08c8b3 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -4,14 +4,6 @@ import java.util.concurrent.Callable; public abstract class BlockBehavior { -// public Object useItemOn(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return superMethod.call(); -// } -// -// public Object useWithoutItem(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return superMethod.call(); -// } - public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return superMethod.call(); } @@ -56,20 +48,4 @@ public abstract class BlockBehavior { public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { } - -// -// public Object getFluidState(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return superMethod.call(); -// } -// public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return (boolean) superMethod.call(); -// } -// -// public boolean placeLiquid(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return (boolean) superMethod.call(); -// } -// -// public Object pickupBlock(Object thisBlock, Object[] args, Callable superMethod) throws Exception { -// return superMethod.call(); -// } } From 71550dd183b129e96195737625a2dff84cffb888 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 13 May 2025 02:57:22 +0800 Subject: [PATCH 55/73] Update ItemEventListener.java --- .../bukkit/item/listener/ItemEventListener.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 225c4187b..9c1d62e4c 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 @@ -73,11 +73,6 @@ public class ItemEventListener implements Listener { Object blockState = BlockStateUtils.blockDataToBlockState(blockData); ImmutableBlockState immutableBlockState = null; int stateId = BlockStateUtils.blockStateToId(blockState); - Item itemInHand = serverPlayer.getItemInHand(hand); - - Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); - boolean hasItem = itemInHand != null; - boolean hasCustomItem = optionalCustomItem.isPresent(); // 处理自定义方块 if (!BlockStateUtils.isVanillaBlock(stateId)) { @@ -98,6 +93,7 @@ public class ItemEventListener implements Listener { event.setCancelled(true); return; } + // run custom functions CustomBlock customBlock = immutableBlockState.owner().value(); PlayerBlockActionContext context = PlayerBlockActionContext.of(serverPlayer, new BukkitBlockInWorld(block), ContextHolder.builder() @@ -112,6 +108,11 @@ public class ItemEventListener implements Listener { else customBlock.execute(context, EventTrigger.LEFT_CLICK); } + Item itemInHand = serverPlayer.getItemInHand(hand); + Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); + boolean hasItem = itemInHand != null; + boolean hasCustomItem = optionalCustomItem.isPresent(); + // interact block with items if (hasItem && action == Action.RIGHT_CLICK_BLOCK) { Location interactionPoint = Objects.requireNonNull(event.getInteractionPoint(), "interaction point should not be null"); From 63ac061cdfb452aa9b96c3674adee15cb991bef8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 13 May 2025 03:23:06 +0800 Subject: [PATCH 56/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=8E=A9=E5=AE=B6?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../context/condition/AllOfCondition.java | 13 ++-- .../context/condition/AnyOfCondition.java | 13 ++-- .../function/AbstractConditionalFunction.java | 4 ++ .../context/function/CommandFunction.java | 2 +- .../context/selector/AllPlayerSelector.java | 22 +++---- .../context/selector/PlayerSelectors.java | 29 ++++++++- .../craftengine/core/util/MCUtils.java | 65 ++++++++++++++++++- 7 files changed, 116 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java index c89b52606..a1776b43d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -11,22 +12,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.function.Predicate; public class AllOfCondition implements Condition { - protected final List> conditions; + protected final Predicate condition; public AllOfCondition(List> conditions) { - this.conditions = conditions; + this.condition = MCUtils.allOf(conditions); } @Override public boolean test(CTX ctx) { - for (Condition condition : conditions) { - if (!condition.test(ctx)) { - return false; - } - } - return true; + return this.condition.test(ctx); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java index 4151e9870..e01568f5b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -11,22 +12,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.function.Predicate; public class AnyOfCondition implements Condition { - protected final List> conditions; + protected final Predicate condition; public AnyOfCondition(List> conditions) { - this.conditions = conditions; + this.condition = MCUtils.anyOf(conditions); } @Override public boolean test(CTX ctx) { - for (Condition condition : conditions) { - if (condition.test(ctx)) { - return true; - } - } - return false; + return this.condition.test(ctx); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java index 7d079994a..394552424 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -35,6 +35,10 @@ public abstract class AbstractConditionalFunction implement this.factory = factory; } + public java.util.function.Function, Condition> conditionFactory() { + return factory; + } + protected List> getPredicates(Map arguments) { Object predicates = arguments.get("conditions"); if (predicates == null) return List.of(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index a6dd5254d..1dc91d843 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -72,7 +72,7 @@ public class CommandFunction extends AbstractConditionalFun Object command = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "command", "commands"), "warning.config.function.command.missing_command"); List commands = MiscUtils.getAsStringList(command).stream().map(TextProviders::fromString).toList(); boolean asPlayer = (boolean) arguments.getOrDefault("as-player", false); - return new CommandFunction<>(getPredicates(arguments), commands, asPlayer, PlayerSelectors.fromObject(arguments.get("target"))); + return new CommandFunction<>(getPredicates(arguments), commands, asPlayer, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory())); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java index 77e431e1a..19330e03e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java @@ -8,42 +8,38 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; public class AllPlayerSelector implements PlayerSelector { - private final List> predicates; + private final Predicate predicate; public AllPlayerSelector(List> predicates) { - this.predicates = predicates; + this.predicate = MCUtils.allOf(predicates); } public AllPlayerSelector() { - this.predicates = List.of(); - } - - public List> predicates() { - return predicates; + this.predicate = null; } @SuppressWarnings("unchecked") @Override public List get(CTX context) { - if (this.predicates.isEmpty()) { + if (this.predicate == null) { return Arrays.asList(CraftEngine.instance().networkManager().onlineUsers()); } else { List players = new ArrayList<>(); - outer: for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { + for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { PlayerOptionalContext newContext = PlayerOptionalContext.of(player, ContextHolder.builder() .withOptionalParameter(CommonParameters.WORLD, context.getOptionalParameter(CommonParameters.WORLD).orElse(null)) .withOptionalParameter(CommonParameters.LOCATION, context.getOptionalParameter(CommonParameters.LOCATION).orElse(null)) ); - for (Condition predicate : this.predicates) { - if (!predicate.test((CTX) newContext)) { - continue outer; - } + if (!this.predicate.test((CTX) newContext)) { + continue; } players.add(player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java index 7008839c3..2887faa49 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java @@ -1,15 +1,21 @@ package net.momirealms.craftengine.core.plugin.context.selector; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.function.Function; public class PlayerSelectors { public static final Key ALL = Key.of("craftengine:all"); public static final Key SELF = Key.of("craftengine:self"); - public static PlayerSelector fromObject(Object object) { + public static PlayerSelector fromObject(Object object, Function, Condition> conditionFactory) { if (object == null) return null; if (object instanceof String string) { if (string.equals("self") || string.equals("@self") || string.equals("@s")) { @@ -18,6 +24,27 @@ public class PlayerSelectors { return new AllPlayerSelector<>(); } } else if (object instanceof Map map) { + Map selectorMap = MiscUtils.castToMap(map, false); + Object typeObj = selectorMap.get("type"); + Object conditionObj = ResourceConfigUtils.get(selectorMap, "conditions"); + if (!(typeObj instanceof String typeString)) { + throw new UnsupportedOperationException("Not supported yet."); + } + if (typeString.equals("all") || typeString.equals("@all") || typeString.equals("@a")) { + List> conditions = new ArrayList<>(); + if (conditionObj instanceof List list) { + @SuppressWarnings("unchecked") + List> conditionList = (List>) list; + for (Map condition : conditionList) { + conditions.add(conditionFactory.apply(condition)); + } + } else if (conditionObj instanceof Map) { + conditions.add(conditionFactory.apply(MiscUtils.castToMap(conditionObj, false))); + } else { + return new AllPlayerSelector<>(); + } + return new AllPlayerSelector<>(conditions); + } } throw new UnsupportedOperationException("Not supported yet."); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 869229f26..dc3c0846c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -116,7 +116,6 @@ public class MCUtils { return false; } } - return true; }; } @@ -148,6 +147,70 @@ public class MCUtils { }; } + public static Predicate anyOf() { + return o -> false; + } + + @SuppressWarnings("unchecked") + public static Predicate anyOf(Predicate a) { + return (Predicate) a; + } + + public static Predicate anyOf(Predicate a, Predicate b) { + return o -> a.test(o) || b.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c) { + return o -> a.test(o) || b.test(o) || c.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d) { + return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d, Predicate e) { + return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o) || e.test(o); + } + + @SafeVarargs + public static Predicate anyOf(Predicate... predicates) { + return o -> { + for (Predicate predicate : predicates) { + if (predicate.test(o)) { + return true; + } + } + return false; + }; + } + + public static Predicate anyOf(List> predicates) { + return switch (predicates.size()) { + case 0 -> anyOf(); + case 1 -> anyOf((Predicate) predicates.get(0)); + case 2 -> anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1)); + case 3 -> anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1), (Predicate) predicates.get(2)); + case 4 -> anyOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3) + ); + case 5 -> anyOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3), + (Predicate) predicates.get(4) + ); + default -> { + @SuppressWarnings("unchecked") + Predicate[] predicates2 = predicates.toArray(Predicate[]::new); + yield anyOf(predicates2); + } + }; + } + public static T findPreviousInIterable(Iterable iterable, @Nullable T object) { Iterator iterator = iterable.iterator(); T previous = null; From 9cde66537c4ca3a5cf16ceb079d684cc1d98b7a0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 13 May 2025 19:25:54 +0800 Subject: [PATCH 57/73] =?UTF-8?q?feat(config):=20=E5=88=AB=E6=A0=B7?= =?UTF-8?q?=E7=9A=84=E6=8A=95=E5=B0=84=E4=B8=89=E5=8F=89=E6=88=9F=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectile/BukkitProjectileManager.java | 52 +- .../entity/projectile/TridentRelease.java | 515 ++++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 114 +++- .../entity/projectile/ProjectileMeta.java | 2 +- .../craftengine/core/item/ItemSettings.java | 3 +- .../craftengine/core/util/MCUtils.java | 10 + gradle.properties | 2 +- 7 files changed, 688 insertions(+), 10 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java 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 164055f18..c82cc6c17 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.entity.projectile; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; +import io.papermc.paper.event.player.PlayerStopUsingItemEvent; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask; @@ -9,22 +11,22 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.projectile.CustomProjectile; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; -import org.bukkit.entity.Arrow; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.ThrowableProjectile; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.inventory.ItemStack; +import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -95,6 +97,48 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { }); } + @EventHandler + public void onPlayerInteract(PlayerItemConsumeEvent event) { + ItemStack item = event.getItem(); + String type = getType(item); + if (type == null) return; + if (type.equals("bow") || type.equals("spear")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onPlayerStopUsingItem(PlayerStopUsingItemEvent event) { + ItemStack item = event.getItem(); + String type = getType(item); + if (type == null) return; + int ticksHeldFor = event.getTicksHeldFor(); + Player player = event.getPlayer(); + if (type.equals("bow")) { + if (ticksHeldFor < 3) return; + // player.sendMessage("可以投出自定义弓: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); + } else if (type.equals("trident")) { + if (ticksHeldFor < 10) return; + // player.sendMessage("可以投出自定义三叉戟: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); + Object nmsItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(item); + Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); + Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player); + boolean success = TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); + player.sendMessage("释放成功: " + success); + } + } + + @Nullable + private String getType(ItemStack item) { + Item wrapped = BukkitItemManager.instance().wrap(item); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) return null; + CustomItem customItem = optionalCustomItem.get(); + ProjectileMeta meta = customItem.settings().projectileMeta(); + if (meta == null) return null; + return meta.type(); + } + public class ProjectileInjectTask implements Runnable { private final Projectile projectile; private final SchedulerTask task; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java new file mode 100644 index 000000000..549b3f8f8 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/TridentRelease.java @@ -0,0 +1,515 @@ +package net.momirealms.craftengine.bukkit.entity.projectile; + +import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; + +public class TridentRelease { + + private TridentRelease() {} + + public static boolean releaseUsing(Object stack, Object level, Object entity) { + if (VersionHelper.isOrAbove1_21_2()) { + return releaseUsing_1_21_2(stack, level, entity); + } else if (VersionHelper.isOrAbove1_21()) { + return releaseUsing_1_21(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20_5()) { + return releaseUsing_1_20_5(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20_3()) { + return releaseUsing_1_20_3(stack, level, entity); + } else if (VersionHelper.isOrAbove1_20()) { + return releaseUsing_1_20(stack, level, entity); + } + return false; + } + + private static boolean releaseUsing_1_21_2(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copyWithCount(stack, 1); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + Object copyStack1 = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack1)) return false; + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack1, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack); + + if (spinStrength == 0.0F) { + Object projectile = FastNMS.INSTANCE.method$Projectile$ThrownTrident$spawnProjectileFromRotationDelayed( + level, + copyStack, + entity, + 0.0F, + 2.5F, + 1.0F + ); + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile)) + ); + + if (!event.callEvent() || !FastNMS.INSTANCE.method$Projectile$Delayed$attemptSpawn(projectile)) { + FastNMS.INSTANCE.method$AbstractContainerMenu$sendAllDataToRemote(FastNMS.INSTANCE.field$Player$containerMenu(entity)); + return false; + } + + Object trident = FastNMS.INSTANCE.method$Projectile$Delayed$projectile(projectile); + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtWithoutBreaking(stack, 1, entity); + FastNMS.INSTANCE.method$ItemStack$consume(stack, 1, entity); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(trident, copyStack1); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(trident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + trident, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_21(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + Object sound = FastNMS.INSTANCE.method$EnchantmentHelper$pickHighestLevel(stack); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, 8.0F, stack); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + FastNMS.INSTANCE.method$Holder$value(sound), + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20_5(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + FastNMS.INSTANCE.method$LivingEntity$getSlotForHand(FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.method$Player$hasInfiniteMaterials(entity)) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20_3(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + (player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$AbstractArrow$pickupItemStack(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$CraftEventFactory$callPlayerRiptideEvent(entity, stack, x, y, z); + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + + private static boolean releaseUsing_1_20(Object stack, Object level, Object entity) { + Object copyStack = FastNMS.INSTANCE.method$ItemStack$copy(stack); + if (FastNMS.INSTANCE.method$ItemStack$isEmpty(copyStack)) return false; + + float spinStrength = FastNMS.INSTANCE.method$EnchantmentHelper$getTridentSpinAttackStrength(stack, entity); + + if ((spinStrength > 0.0F && !FastNMS.INSTANCE.method$Entity$isInWaterOrRain(entity)) || FastNMS.INSTANCE.method$ItemStack$nextDamageWillBreak(stack)) { + return false; + } + FastNMS.INSTANCE.method$ItemStack$setDamageValue(copyStack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + + if (spinStrength == 0.0F) { + Object entitythrowntrident = FastNMS.INSTANCE.constructor$ThrownTrident(level, entity, stack); + FastNMS.INSTANCE.method$ThrownTrident$shootFromRotation( + entitythrowntrident, + entity, + FastNMS.INSTANCE.method$Entity$getXRot(entity), + FastNMS.INSTANCE.method$Entity$getYRot(entity), + 0.0F, 2.5F, 1.0F + ); + if (FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.field$AbstractArrow$pickup(entitythrowntrident, Reflections.instance$AbstractArrow$Pickup$CREATIVE_ONLY); + } + + PlayerLaunchProjectileEvent event = new PlayerLaunchProjectileEvent( + (Player) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity), + FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(stack), + (Projectile) FastNMS.INSTANCE.method$Entity$getBukkitEntity(entitythrowntrident) + ); + if (!event.callEvent() || !FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, entitythrowntrident)) { + Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity); + if (bukkitEntity instanceof Player player) { + player.updateInventory(); + } + + return false; + } + + if (event.shouldConsume()) { + FastNMS.INSTANCE.method$ItemStack$hurtAndBreak( + stack, 1, entity, + (player1) -> FastNMS.INSTANCE.method$LivingEntity$broadcastBreakEvent(player1, FastNMS.INSTANCE.method$LivingEntity$getUsedItemHand(entity)) + ); + } + + FastNMS.INSTANCE.field$ThrownTrident$tridentItem(entitythrowntrident, copyStack); + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entitythrowntrident, + Reflections.instance$SoundEvent$TRIDENT_THROW, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + if (event.shouldConsume() && !FastNMS.INSTANCE.field$Abilities$instabuild(FastNMS.INSTANCE.method$Player$getAbilities(entity))) { + FastNMS.INSTANCE.method$Inventory$removeItem(FastNMS.INSTANCE.method$Player$getInventory(entity), stack); + } + return true; + } + + float yaw = FastNMS.INSTANCE.method$Entity$getYRot(entity); + float pitch = FastNMS.INSTANCE.method$Entity$getXRot(entity); + float x = -MCUtils.sin(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + float y = -MCUtils.sin(pitch * MCUtils.DEG_TO_RAD); + float z = MCUtils.cos(yaw * MCUtils.DEG_TO_RAD) * MCUtils.cos(pitch * MCUtils.DEG_TO_RAD); + + float length = MCUtils.sqrt(x * x + y * y + z * z); + x = x / length * spinStrength; + y = y / length * spinStrength; + z = z / length * spinStrength; + + FastNMS.INSTANCE.method$Entity$push(entity, x, y, z); + FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true); + FastNMS.INSTANCE.method$ItemStack$setDamageValue(stack, FastNMS.INSTANCE.method$ItemStack$getDamageValue(stack) + 1); + FastNMS.INSTANCE.method$Player$startAutoSpinAttack(entity, 20, -1.0F, null); + + if (FastNMS.INSTANCE.method$Entity$onGround(entity)) { + FastNMS.INSTANCE.method$Entity$move(entity, Reflections.instance$MoverType$SELF, FastNMS.INSTANCE.constructor$Vec3(0.0D, 1.1999999D, 0.0D)); + } + + Object soundeffect; + if (spinStrength >= 3) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_3; + } else if (spinStrength == 2) { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_2; + } else { + soundeffect = Reflections.instance$SoundEvent$TRIDENT_RIPTIDE_1; + } + + FastNMS.INSTANCE.method$Level$playSound( + level, + null, + entity, + soundeffect, + Reflections.instance$SoundSource$PLAYERS, + 1.0F, 1.0F + ); + return true; + } + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 679a26279..345e6a05c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -3367,11 +3367,23 @@ public class Reflections { ); public static final Object instance$SoundEvent$EMPTY; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_1; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_2; + public static final Object instance$SoundEvent$TRIDENT_RIPTIDE_3; + public static final Object instance$SoundEvent$TRIDENT_THROW; static { try { - Object key = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "intentionally_empty"); - instance$SoundEvent$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, key); + Object intentionallyEmpty = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "intentionally_empty"); + instance$SoundEvent$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, intentionallyEmpty); + Object tridentRiptide1 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident_riptide_1"); + instance$SoundEvent$TRIDENT_RIPTIDE_1 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide1); + Object tridentRiptide2 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident_riptide_2"); + instance$SoundEvent$TRIDENT_RIPTIDE_2 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide2); + Object tridentRiptide3 = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident.riptide_3"); + instance$SoundEvent$TRIDENT_RIPTIDE_3 = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentRiptide3); + Object tridentThrow = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.trident.throw"); + instance$SoundEvent$TRIDENT_THROW = method$Registry$get.invoke(instance$BuiltInRegistries$SOUND_EVENT, tridentThrow); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6668,11 +6680,107 @@ public class Reflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundCustomPayloadPacket) + ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) ); // 1.20.2+ public static final Constructor constructor$DiscardedPayload = Optional.ofNullable(clazz$DiscardedPayload) .map(clazz -> ReflectionUtils.getTheOnlyConstructor(clazz)) .orElse(null); + + public static final Method method$SoundSource$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$SoundSource, clazz$SoundSource.arrayType() + ) + ); + + public static final Object instance$SoundSource$MASTER; + public static final Object instance$SoundSource$MUSIC; + public static final Object instance$SoundSource$RECORDS; + public static final Object instance$SoundSource$WEATHER; + public static final Object instance$SoundSource$BLOCKS; + public static final Object instance$SoundSource$HOSTILE; + public static final Object instance$SoundSource$NEUTRAL; + public static final Object instance$SoundSource$PLAYERS; + public static final Object instance$SoundSource$AMBIENT; + public static final Object instance$SoundSource$VOICE; + + static { + try { + Object[] values = (Object[]) method$SoundSource$values.invoke(null); + instance$SoundSource$MASTER = values[0]; + instance$SoundSource$MUSIC = values[1]; + instance$SoundSource$RECORDS = values[2]; + instance$SoundSource$WEATHER = values[3]; + instance$SoundSource$BLOCKS = values[4]; + instance$SoundSource$HOSTILE = values[5]; + instance$SoundSource$NEUTRAL = values[6]; + instance$SoundSource$PLAYERS = values[7]; + instance$SoundSource$AMBIENT = values[8]; + instance$SoundSource$VOICE = values[9]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + public static final Class clazz$MoverType = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.EnumMoveType", + "world.entity.MoverType" + ) + ); + + public static final Method method$MoverType$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$MoverType, clazz$MoverType.arrayType() + ) + ); + + public static final Object instance$MoverType$SELF; + public static final Object instance$MoverType$PLAYER; + public static final Object instance$MoverType$PISTON; + public static final Object instance$MoverType$SHULKER_BOX; + public static final Object instance$MoverType$SHULKER; + + static { + try { + Object[] values = (Object[]) method$MoverType$values.invoke(null); + instance$MoverType$SELF = values[0]; + instance$MoverType$PLAYER = values[1]; + instance$MoverType$PISTON = values[2]; + instance$MoverType$SHULKER_BOX = values[3]; + instance$MoverType$SHULKER = values[4]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + public static final Class clazz$AbstractArrow$Pickup = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.EntityArrow$PickupStatus", + "world.entity.projectile.AbstractArrow$Pickup" + ) + ); + + public static final Method method$AbstractArrow$Pickup$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$AbstractArrow$Pickup, clazz$AbstractArrow$Pickup.arrayType() + ) + ); + + public static final Object instance$AbstractArrow$Pickup$DISALLOWED; + public static final Object instance$AbstractArrow$Pickup$ALLOWED; + public static final Object instance$AbstractArrow$Pickup$CREATIVE_ONLY; + + static { + try { + Object[] values = (Object[]) method$AbstractArrow$Pickup$values.invoke(null); + instance$AbstractArrow$Pickup$DISALLOWED = values[0]; + instance$AbstractArrow$Pickup$ALLOWED = values[1]; + instance$AbstractArrow$Pickup$CREATIVE_ONLY = values[2]; + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java index a7fde9ad4..9f0337be0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java @@ -5,5 +5,5 @@ import net.momirealms.craftengine.core.util.Key; import org.joml.Quaternionf; import org.joml.Vector3f; -public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation) { +public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation, String type) { } 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 bc8f9960f..c2f41b13c 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 @@ -226,7 +226,8 @@ public class ItemSettings { Vector3f translation = MiscUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation"); Vector3f scale = MiscUtils.getAsVector3f(args.getOrDefault("scale", "1"), "scale"); Quaternionf rotation = MiscUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation-left", "rotation"), "rotation-left"); - return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation)); + String type = args.getOrDefault("type", "none").toString(); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation, type)); })); registerFactory("dyeable", (value -> { boolean bool = (boolean) value; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 869229f26..5ead78a3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -12,6 +12,8 @@ public class MCUtils { private MCUtils() {} + public static final float DEG_TO_RAD = ((float)Math.PI / 180F); + private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; private static final float[] SIN = make(new float[65536], (sineTable) -> { for(int i = 0; i < sineTable.length; ++i) { @@ -168,6 +170,14 @@ public class MCUtils { return SIN[(int) (value * 10430.378F) & '\uffff']; } + public static float cos(float value) { + return SIN[(int)(value * 10430.378F + 16384.0F) & '\uffff']; + } + + public static float sqrt(float value) { + return (float)Math.sqrt(value); + } + public static T findNextInIterable(Iterable iterable, @Nullable T object) { Iterator iterator = iterable.iterator(); T next = iterator.next(); diff --git a/gradle.properties b/gradle.properties index ec72047d6..31dd432b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.21 +nms_helper_version=0.65.23 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 5eb0b5c2851d385dbb01a87d9f0fd653e0813fcd Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 13 May 2025 19:30:46 +0800 Subject: [PATCH 58/73] =?UTF-8?q?feat(bukkit):=20=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E8=B0=83=E8=AF=95=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/entity/projectile/BukkitProjectileManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c82cc6c17..3d3ad8f87 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 @@ -124,7 +124,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player); boolean success = TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); - player.sendMessage("释放成功: " + success); + // player.sendMessage("释放成功: " + success); } } From 0930af38e67227647b862a2b9a12b11ac2550089 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 13 May 2025 23:15:33 +0800 Subject: [PATCH 59/73] =?UTF-8?q?=E9=87=8D=E6=9E=84context=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineBlocks.java | 15 ++-- .../bukkit/api/CraftEngineFurniture.java | 20 ++--- .../bukkit/block/BlockEventListener.java | 53 ++++++------ .../bukkit/block/BukkitBlockManager.java | 12 +-- .../bukkit/block/BukkitCustomBlock.java | 4 +- .../block/FallingBlockRemoveListener.java | 24 ++---- .../block/behavior/BushBlockBehavior.java | 14 ++-- .../block/behavior/CropBlockBehavior.java | 7 +- .../block/behavior/FallingBlockBehavior.java | 19 ++--- .../block/behavior/LeavesBlockBehavior.java | 10 +-- .../behavior/SugarCaneBlockBehavior.java | 12 +-- .../bukkit/entity/BukkitEntity.java | 10 +-- .../item/listener/ItemEventListener.java | 15 ++-- .../bukkit/loot/BukkitVanillaLootManager.java | 15 ++-- .../plugin/user/BukkitServerPlayer.java | 24 +++--- .../bukkit/util/LocationUtils.java | 5 ++ .../bukkit/world/BukkitBlockInWorld.java | 16 ++-- .../craftengine/bukkit/world/BukkitWorld.java | 16 ++-- .../craftengine/core/block/CustomBlock.java | 14 ++-- .../core/block/ImmutableBlockState.java | 8 +- .../core/entity/AbstractEntity.java | 6 +- .../craftengine/core/entity/Entity.java | 4 +- .../core/entity/player/Player.java | 2 + .../core/font/EmojiParameters.java | 4 +- .../core/item/ItemBuildContext.java | 6 +- .../loot/entry/ExpLootEntryContainer.java | 6 +- .../FurnitureItemLootEntryContainer.java | 4 +- .../entry/SingleItemLootEntryContainer.java | 4 +- .../function/ApplyBonusCountFunction.java | 4 +- .../core/loot/function/DropExpFunction.java | 6 +- .../loot/function/ExplosionDecayFunction.java | 4 +- .../AbstractAdditionalParameterContext.java | 42 ---------- .../AbstractChainParameterContext.java | 48 +++++++++++ .../plugin/context/AbstractCommonContext.java | 29 ++++--- .../context/AdditionalParameterProvider.java | 8 ++ .../context/ChainParameterProvider.java | 8 ++ .../CommonParameterProvider.java | 11 ++- .../core/plugin/context/Context.java | 4 +- .../core/plugin/context/ContextHolder.java | 4 +- .../core/plugin/context/ContextKey.java | 82 ++++++++++++++----- .../context/LazyContextParameterProvider.java | 21 ----- .../context/PlayerBlockActionContext.java | 21 ----- .../context/PlayerFurnitureActionContext.java | 20 ----- .../plugin/context/PlayerOptionalContext.java | 21 ++--- .../context/condition/ClickTypeCondition.java | 4 +- .../context/condition/CommonConditions.java | 1 + .../context/condition/DistanceCondition.java | 17 ++-- .../condition/EnchantmentCondition.java | 4 +- .../condition/FallingBlockCondition.java | 4 +- .../MatchBlockPropertyCondition.java | 4 +- .../context/condition/MatchItemCondition.java | 4 +- .../context/condition/RandomCondition.java | 7 +- .../condition/SurvivesExplosionCondition.java | 4 +- .../condition/TableBonusCondition.java | 4 +- .../context/function/CommandFunction.java | 4 +- .../context/function/CommonFunctions.java | 19 ++++- .../context/function/MessageFunction.java | 70 ++++++++++++++++ .../parameter/BlockParameterProvider.java | 35 ++++---- .../context/parameter/BlockParameters.java | 19 ----- .../parameter/ChainContextParameters.java | 10 +++ .../context/parameter/CommonParameters.java | 24 ------ .../parameter/DirectContextParameters.java | 42 ++++++++++ .../parameter/PlayerParameterProvider.java | 41 ++++------ .../context/parameter/PlayerParameters.java | 24 ------ .../parameter/PositionParameterProvider.java | 31 +++++++ .../parameter/WorldParameterProvider.java | 24 ++++++ .../context/selector/AllPlayerSelector.java | 5 +- .../context/selector/SelfPlayerSelector.java | 4 +- .../plugin/event/BlockEventConditions.java | 12 +-- .../plugin/event/BlockEventFunctions.java | 10 +-- .../core/plugin/gui/GuiParameters.java | 12 +-- .../text/minimessage/NamedArgumentTag.java | 2 +- .../core/registry/BuiltInRegistries.java | 6 +- .../craftengine/core/registry/Registries.java | 6 +- .../craftengine/core/world/BlockInWorld.java | 14 +++- .../craftengine/core/world/World.java | 10 ++- .../craftengine/core/world/WorldPosition.java | 23 +++++- gradle.properties | 2 +- 78 files changed, 664 insertions(+), 520 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/AdditionalParameterProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/ChainParameterProvider.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/context/{parameter => }/CommonParameterProvider.java (67%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 17a8d21b4..73ad40632 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -12,11 +12,12 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.Location; import org.bukkit.Material; @@ -169,20 +170,20 @@ public final class CraftEngineBlocks { if (state == null || state.isEmpty()) return false; World world = new BukkitWorld(block.getWorld()); Location location = block.getLocation(); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); if (dropLoot) { - ContextHolder.Builder builder = new ContextHolder.Builder().withParameter(CommonParameters.WORLD, world).withParameter(CommonParameters.LOCATION, vec3d); + ContextHolder.Builder builder = new ContextHolder.Builder() + .withParameter(DirectContextParameters.POSITION, position); BukkitServerPlayer serverPlayer = BukkitCraftEngine.instance().adapt(player); if (player != null) { - builder.withParameter(CommonParameters.PLAYER, serverPlayer); - //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withParameter(DirectContextParameters.PLAYER, serverPlayer); } for (Item item : state.getDrops(builder, world, serverPlayer)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } if (playSound) { - world.playBlockSound(vec3d, state.sounds().breakSound()); + world.playBlockSound(position, state.sounds().breakSound()); } if (sendParticles) { FastNMS.INSTANCE.method$Level$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 51fb36cd4..cb32e11ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -13,10 +13,11 @@ import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -267,24 +268,23 @@ public final class CraftEngineFurniture { Location location = loadedFurniture.dropLocation(); loadedFurniture.destroy(); LootTable lootTable = (LootTable) loadedFurniture.config().lootTable(); - Vec3d vec3d = LocationUtils.toVec3d(location); World world = new BukkitWorld(location.getWorld()); + WorldPosition position = new WorldPosition(world, location.getX(), location.getY(), location.getZ()); if (dropLoot && lootTable != null) { - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(CommonParameters.LOCATION, vec3d); - builder.withParameter(CommonParameters.WORLD, world); - builder.withOptionalParameter(CommonParameters.FURNITURE_ITEM, loadedFurniture.extraData().item().orElse(null)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.FURNITURE, loadedFurniture) + .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, loadedFurniture.extraData().item().orElse(null)); if (player != null) { - builder.withParameter(CommonParameters.PLAYER, player); - //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, player.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withParameter(DirectContextParameters.PLAYER, player); } List> items = lootTable.getRandomItems(builder.build(), world, player); for (Item item : items) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } if (playSound) { - world.playBlockSound(vec3d, loadedFurniture.config().settings().sounds().breakSound()); + world.playBlockSound(position, loadedFurniture.config().settings().sounds().breakSound()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index e3b9f07cd..013583c6d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -14,10 +14,11 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -146,8 +147,8 @@ public class BlockEventListener implements Listener { } } // play sound - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - world.playBlockSound(vec3d, state.sounds().breakSound()); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + world.playBlockSound(position, state.sounds().breakSound()); if (player.getGameMode() == GameMode.CREATIVE || !customBreakEvent.dropItems()) { return; } @@ -160,12 +161,11 @@ public class BlockEventListener implements Listener { // drop items ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(CommonParameters.WORLD, world) - .withParameter(CommonParameters.LOCATION, vec3d) - .withParameter(CommonParameters.PLAYER, serverPlayer); + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.PLAYER, serverPlayer); //mark item .withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, itemInHand); for (Item item : state.getDrops(builder, world, serverPlayer)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } } else { @@ -179,16 +179,14 @@ public class BlockEventListener implements Listener { Location location = block.getLocation(); BukkitServerPlayer serverPlayer = this.plugin.adapt(player); net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(CommonParameters.WORLD, world) - .withParameter(CommonParameters.LOCATION, vec3d) - .withParameter(CommonParameters.PLAYER, serverPlayer); - //mark item .withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.PLAYER, serverPlayer); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { for (Item item : lootTable.getRandomItems(contextHolder, world, serverPlayer)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } }); @@ -221,12 +219,11 @@ public class BlockEventListener implements Listener { if (!immutableBlockState.isEmpty()) { Location location = block.getLocation(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(block.getWorld()); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(CommonParameters.WORLD, world) - .withParameter(CommonParameters.LOCATION, vec3d); + .withParameter(DirectContextParameters.POSITION, position); for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } } else { @@ -238,15 +235,14 @@ public class BlockEventListener implements Listener { } Location location = block.getLocation(); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(CommonParameters.WORLD, world); - builder.withParameter(CommonParameters.LOCATION, vec3d); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { for (Item item : lootTable.getRandomItems(contextHolder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } }); @@ -336,17 +332,16 @@ public class BlockEventListener implements Listener { BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); ImmutableBlockState state = manager.getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); if (state != null && !state.isEmpty()) { - ContextHolder.Builder builder = ContextHolder.builder(); - Vec3d vec3d = Vec3d.atCenterOf(blockPos); - builder.withParameter(CommonParameters.LOCATION, vec3d); - builder.withParameter(CommonParameters.WORLD, world); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(blockPos)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); if (yield < 1f) { - builder.withParameter(CommonParameters.EXPLOSION_RADIUS, 1.0f / yield); + builder.withParameter(DirectContextParameters.EXPLOSION_RADIUS, 1.0f / yield); } for (Item item : state.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } - world.playBlockSound(vec3d, state.sounds().breakSound()); + world.playBlockSound(position, state.sounds().breakSound()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 84f1098d6..0fa67030c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -23,7 +23,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.BlockEventFunctions; import net.momirealms.craftengine.core.plugin.event.EventTrigger; @@ -459,7 +459,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } Object eventsObj = ResourceConfigUtils.get(section, "events", "event"); - EnumMap>> events = parseEvents(eventsObj); + EnumMap>> events = parseEvents(eventsObj); Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) @@ -513,8 +513,8 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private EnumMap>> parseEvents(Object eventsObj) { - EnumMap>> events = new EnumMap<>(EventTrigger.class); + private EnumMap>> parseEvents(Object eventsObj) { + EnumMap>> events = new EnumMap<>(EventTrigger.class); if (eventsObj instanceof Map eventsSection) { Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { @@ -529,7 +529,7 @@ public class BukkitBlockManager extends AbstractBlockManager { BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) )); } else { - List> eventsList = new ArrayList<>(); + List> eventsList = new ArrayList<>(); for (Object event : list) { eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); } @@ -552,7 +552,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } try { EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); - Function function = BlockEventFunctions.fromMap(eventSection); + Function function = BlockEventFunctions.fromMap(eventSection); events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); } catch (IllegalArgumentException e) { throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index e0c550bdf..17891cded 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -37,7 +37,7 @@ public class BukkitCustomBlock extends CustomBlock { Map appearances, Map variantMapper, BlockSettings settings, - @NotNull EnumMap>> events, + @NotNull EnumMap>> events, @Nullable Map behavior, @Nullable LootTable lootTable ) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java index 20e17db9d..60510e94a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java @@ -7,19 +7,15 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.entity.FallingBlock; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class FallingBlockRemoveListener implements Listener { - /* - * This is not an event that would be removed - * Paper mistakenly marked it as deprecated in 1.20.4 - */ - @SuppressWarnings("removal") @EventHandler public void onFallingBlockBreak(org.bukkit.event.entity.EntityRemoveEvent event) { if (event.getCause() == org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP && event.getEntity() instanceof FallingBlock fallingBlock) { @@ -31,22 +27,18 @@ public class FallingBlockRemoveListener implements Listener { int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(CommonParameters.FALLING_BLOCK, true); - double x = Reflections.field$Entity$xo.getDouble(fallingBlockEntity); - double y = Reflections.field$Entity$yo.getDouble(fallingBlockEntity); - double z = Reflections.field$Entity$zo.getDouble(fallingBlockEntity); - Vec3d vec3d = new Vec3d(x, y, z); net.momirealms.craftengine.core.world.World world = new BukkitWorld(fallingBlock.getWorld()); - builder.withParameter(CommonParameters.LOCATION, vec3d); - builder.withParameter(CommonParameters.WORLD, world); + WorldPosition position = new WorldPosition(world, Reflections.field$Entity$xo.getDouble(fallingBlockEntity), Reflections.field$Entity$yo.getDouble(fallingBlockEntity), Reflections.field$Entity$zo.getDouble(fallingBlockEntity)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.FALLING_BLOCK, true) + .withParameter(DirectContextParameters.POSITION, position); for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity); boolean isSilent = (boolean) Reflections.method$SynchedEntityData$get.invoke(entityData, Reflections.instance$Entity$DATA_SILENT); if (!isSilent) { - world.playBlockSound(vec3d, immutableBlockState.sounds().destroySound()); + world.playBlockSound(position, immutableBlockState.sounds().destroySound()); } } catch (ReflectiveOperationException e) { CraftEngine.instance().logger().warn("Failed to handle EntityRemoveEvent", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 06b6bac69..381c9152f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -12,7 +12,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.Tuple; @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -67,16 +68,15 @@ public class BushBlockBehavior extends BukkitBlockBehavior { int stateId = BlockStateUtils.blockStateToId(state); ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (previousState != null && !previousState.isEmpty()) { - ContextHolder.Builder builder = ContextHolder.builder(); BlockPos pos = LocationUtils.fromBlockPos(blockPos); - Vec3d vec3d = Vec3d.atCenterOf(pos); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - builder.withParameter(CommonParameters.LOCATION, vec3d); - builder.withParameter(CommonParameters.WORLD, world); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); for (Item item : previousState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } - world.playBlockSound(vec3d, previousState.sounds().breakSound()); + world.playBlockSound(position, previousState.sounds().breakSound()); FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); } return Reflections.method$Block$defaultBlockState.invoke(Reflections.instance$Blocks$AIR); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index e4e6be99d..29b2f7e4e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -16,12 +16,13 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.SimpleContext; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3i; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.World; @@ -148,8 +149,8 @@ public class CropBlockBehavior extends BushBlockBehavior { int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt( SimpleContext.of( ContextHolder.builder() - .withParameter(CommonParameters.WORLD, new BukkitWorld(world)) - .withParameter(CommonParameters.LOCATION, Vec3d.atCenterOf(new Vec3i(x, y, z))) + .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(world), Vec3d.atCenterOf(new Vec3i(x, y, z)))) .build() ) ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index f90956c5f..fb98a3e5f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -11,10 +11,11 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.Map; @@ -90,22 +91,18 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(CommonParameters.FALLING_BLOCK, true); - double x = Reflections.field$Entity$xo.getDouble(fallingBlockEntity); - double y = Reflections.field$Entity$yo.getDouble(fallingBlockEntity); - double z = Reflections.field$Entity$zo.getDouble(fallingBlockEntity); - Vec3d vec3d = new Vec3d(x, y, z); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - builder.withParameter(CommonParameters.LOCATION, vec3d); - builder.withParameter(CommonParameters.WORLD, world); + WorldPosition position = new WorldPosition(world, Reflections.field$Entity$xo.getDouble(fallingBlockEntity), Reflections.field$Entity$yo.getDouble(fallingBlockEntity), Reflections.field$Entity$zo.getDouble(fallingBlockEntity)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.FALLING_BLOCK, true) + .withParameter(DirectContextParameters.POSITION, position); for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } Object entityData = Reflections.field$Entity$entityData.get(fallingBlockEntity); boolean isSilent = (boolean) Reflections.method$SynchedEntityData$get.invoke(entityData, Reflections.instance$Entity$DATA_SILENT); if (!isSilent) { - world.playBlockSound(vec3d, immutableBlockState.sounds().destroySound()); + world.playBlockSound(position, immutableBlockState.sounds().destroySound()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index cf88d726f..0da9cba81 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -14,13 +14,14 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -122,13 +123,12 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { if (isWaterLogged(immutableBlockState)) { bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData()); } - Vec3d vec3d = Vec3d.atCenterOf(pos); net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(CommonParameters.LOCATION, vec3d) - .withParameter(CommonParameters.WORLD, world); + .withParameter(DirectContextParameters.POSITION, position); for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index 1deb5712f..7606c343c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -14,11 +14,12 @@ import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.List; @@ -58,15 +59,14 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { if (currentState != null && !currentState.isEmpty()) { // break the sugar cane FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); - Vec3d vec3d = Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos))); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(CommonParameters.LOCATION, vec3d) - .withParameter(CommonParameters.WORLD, world); + .withParameter(DirectContextParameters.POSITION, position); for (Item item : currentState.getDrops(builder, world, null)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } - world.playBlockSound(vec3d, currentState.sounds().breakSound()); + world.playBlockSound(position, currentState.sounds().breakSound()); FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index ce7748ec8..536217d46 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -18,17 +18,17 @@ public class BukkitEntity extends AbstractEntity { @Override public double x() { - return literalObject().getLocation().getX(); + return literalObject().getX(); } @Override public double y() { - return literalObject().getLocation().getY(); + return literalObject().getY(); } @Override public double z() { - return literalObject().getLocation().getZ(); + return literalObject().getZ(); } @Override @@ -42,12 +42,12 @@ public class BukkitEntity extends AbstractEntity { @Override public float getXRot() { - return literalObject().getLocation().getYaw(); + return literalObject().getYaw(); } @Override public float getYRot() { - return literalObject().getLocation().getPitch(); + return literalObject().getPitch(); } @Override 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 9c1d62e4c..424c35b6a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -15,8 +15,8 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.ClickType; import net.momirealms.craftengine.core.util.Direction; @@ -96,12 +96,11 @@ public class ItemEventListener implements Listener { // run custom functions CustomBlock customBlock = immutableBlockState.owner().value(); - PlayerBlockActionContext context = PlayerBlockActionContext.of(serverPlayer, new BukkitBlockInWorld(block), ContextHolder.builder() - .withParameter(CommonParameters.BLOCK_STATE, immutableBlockState) - .withParameter(CommonParameters.PLAYER, serverPlayer) - .withParameter(CommonParameters.WORLD, serverPlayer.world()) - .withParameter(CommonParameters.LOCATION, new Vec3d(block.getX(), block.getY(), block.getZ())) - .withParameter(CommonParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT) + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.PLAYER, serverPlayer) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT) .build()); customBlock.execute(context, EventTrigger.CLICK); if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 5875827ee..c64de703d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -14,10 +14,11 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -65,22 +66,20 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme } Location location = entity.getLocation(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(entity.getWorld()); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(CommonParameters.WORLD, world); - builder.withParameter(CommonParameters.LOCATION, vec3d); + WorldPosition position = new WorldPosition(world, location.getX(), location.getY(), location.getZ()); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); BukkitServerPlayer optionalPlayer = null; if (VersionHelper.isOrAbove1_20_5()) { if (event.getDamageSource().getCausingEntity() instanceof Player player) { optionalPlayer = this.plugin.adapt(player); - builder.withParameter(CommonParameters.PLAYER, optionalPlayer); - //mark item builder.withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withParameter(DirectContextParameters.PLAYER, optionalPlayer); } } ContextHolder contextHolder = builder.build(); for (LootTable lootTable : loot.lootTables()) { for (Item item : lootTable.getRandomItems(contextHolder, world, optionalPlayer)) { - world.dropItemNaturally(vec3d, item); + world.dropItemNaturally(position, item); } } }); 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 590515847..1d4086b39 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 @@ -171,12 +171,14 @@ public class BukkitServerPlayer extends Player { @Override public void sendActionBar(Component text) { - try { - Object packet = Reflections.constructor$ClientboundSetActionBarTextPacket.newInstance(ComponentUtils.adventureToMinecraft(text)); - sendPacket(packet, false); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to send action bar", e); - } + Object packet = FastNMS.INSTANCE.constructor$ClientboundActionBarPacket(ComponentUtils.adventureToMinecraft(text)); + sendPacket(packet, false); + } + + @Override + public void sendMessage(Component text, boolean overlay) { + Object packet = FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(text), overlay); + sendPacket(packet, false); } @Override @@ -657,12 +659,12 @@ public class BukkitServerPlayer extends Player { @Override public float getYRot() { - return platformPlayer().getLocation().getPitch(); + return platformPlayer().getPitch(); } @Override public float getXRot() { - return platformPlayer().getLocation().getYaw(); + return platformPlayer().getYaw(); } @Override @@ -689,17 +691,17 @@ public class BukkitServerPlayer extends Player { @Override public double x() { - return platformPlayer().getLocation().getX(); + return platformPlayer().getX(); } @Override public double y() { - return platformPlayer().getLocation().getY(); + return platformPlayer().getY(); } @Override public double z() { - return platformPlayer().getLocation().getZ(); + return platformPlayer().getZ(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index 8e4fb070e..bb3d7feec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; @@ -16,6 +17,10 @@ public class LocationUtils { return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.xRot(), position.yRot()); } + public static WorldPosition toWorldPosition(Location location) { + return new WorldPosition(new BukkitWorld(location.getWorld()), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + public static Vec3d toVec3d(Location loc) { return new Vec3d(loc.getX(), loc.getY(), loc.getZ()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java index a7dc16a3d..67c8e080c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java @@ -6,9 +6,9 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; @@ -86,21 +86,17 @@ public class BukkitBlockInWorld implements BlockInWorld { } @Override - public String getAsString() { - ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(this.block); - if (state != null) { - return state.toString(); - } - return this.block.getBlockData().getAsString(); + public ImmutableBlockState customBlockState() { + return CraftEngineBlocks.getCustomBlockState(this.block); } @Override - public Key owner() { + public CustomBlock customBlock() { ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(this.block); if (state != null) { - return state.owner().value().id(); + return state.owner().value(); } - return KeyUtils.namespacedKey2Key(this.block.getType().getKey()); + return null; } public Block block() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 5223b9bd4..c8326c920 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -6,10 +6,7 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.BlockInWorld; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; -import net.momirealms.craftengine.core.world.WorldHeight; +import net.momirealms.craftengine.core.world.*; import org.bukkit.Location; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; @@ -71,7 +68,7 @@ public class BukkitWorld implements World { } @Override - public void dropItemNaturally(Vec3d location, Item item) { + public void dropItemNaturally(Position location, Item item) { ItemStack itemStack = (ItemStack) item.load(); if (ItemUtils.isEmpty(itemStack)) return; if (VersionHelper.isOrAbove1_21_2()) { @@ -82,7 +79,7 @@ public class BukkitWorld implements World { } @Override - public void dropExp(Vec3d location, int amount) { + public void dropExp(Position location, int amount) { if (amount <= 0) return; EntityUtils.spawnEntity(platformWorld(), new Location(platformWorld(), location.x(), location.y(), location.z()), EntityType.EXPERIENCE_ORB, (e) -> { ExperienceOrb orb = (ExperienceOrb) e; @@ -91,7 +88,12 @@ public class BukkitWorld implements World { } @Override - public void playBlockSound(Vec3d location, Key sound, float volume, float pitch) { + public void playBlockSound(Position location, Key sound, float volume, float pitch) { platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); } + + @Override + public long time() { + return platformWorld().getTime(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 6ce564f82..73c324414 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -29,7 +29,7 @@ public abstract class CustomBlock { protected final BlockBehavior behavior; protected final List> placements; protected final ImmutableBlockState defaultState; - protected final EnumMap>> events; + protected final EnumMap>> events; @Nullable protected final LootTable lootTable; @@ -40,7 +40,7 @@ public abstract class CustomBlock { @NotNull Map appearances, @NotNull Map variantMapper, @NotNull BlockSettings settings, - @NotNull EnumMap>> events, + @NotNull EnumMap>> events, @Nullable Map behavior, @Nullable LootTable lootTable ) { @@ -93,8 +93,8 @@ public abstract class CustomBlock { return lootTable; } - public void execute(PlayerBlockActionContext context, EventTrigger trigger) { - for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { function.run(context); } } @@ -177,13 +177,13 @@ public abstract class CustomBlock { protected BlockSettings settings; protected Map behavior; protected LootTable lootTable; - protected EnumMap>> events; + protected EnumMap>> events; protected Builder(Key id) { this.id = id; } - public Builder events(EnumMap>> events) { + public Builder events(EnumMap>> events) { this.events = events; return this; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 30be17f0c..772468379 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -138,16 +138,12 @@ public class ImmutableBlockState extends BlockStateHolder { return state.with(property, (T) value); } - public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world) { - return this.getDrops(builder, world, null); - } - @SuppressWarnings("unchecked") public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world, @Nullable Player player) { CustomBlock block = owner.value(); if (block == null) return List.of(); LootTable lootTable = (LootTable) block.lootTable(); if (lootTable == null) return List.of(); - return lootTable.getRandomItems(builder.withParameter(CommonParameters.BLOCK_STATE, this).build(), world, player); + return lootTable.getRandomItems(builder.withParameter(DirectContextParameters.BLOCK_STATE, this).build(), world, player); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java index ae64546e9..c9eb5a247 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java @@ -1,11 +1,11 @@ package net.momirealms.craftengine.core.entity; -import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; public abstract class AbstractEntity implements Entity { @Override - public Vec3d position() { - return new Vec3d(x(), y(), z()); + public WorldPosition position() { + return new WorldPosition(world(), x(), y(), z(), getXRot(), getYRot()); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index d1e4428e4..8c9958a36 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.entity; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; public interface Entity { Key type(); @@ -14,7 +14,7 @@ public interface Entity { double z(); - Vec3d position(); + WorldPosition position(); void tick(); 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 dccc2734f..81a9b77c3 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 @@ -58,6 +58,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void sendActionBar(Component text); + public abstract void sendMessage(Component text, boolean overlay); + public abstract boolean updateLastSuccessfulInteractionTick(int tick); public abstract int lastSuccessfulInteractionTick(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java b/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java index 5cf91415a..ff72812aa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/EmojiParameters.java @@ -5,6 +5,6 @@ import net.momirealms.craftengine.core.plugin.context.ContextKey; public final class EmojiParameters { private EmojiParameters() {} - public static final ContextKey KEYWORD = ContextKey.of("keyword"); - public static final ContextKey EMOJI = ContextKey.of("emoji"); + public static final ContextKey KEYWORD = ContextKey.direct("keyword"); + public static final ContextKey EMOJI = ContextKey.direct("emoji"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java index 521907dc3..a8b7dd219 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,13 +23,13 @@ public class ItemBuildContext extends PlayerOptionalContext { @NotNull public static ItemBuildContext of(@Nullable Player player, @NotNull ContextHolder.Builder builder) { - if (player != null) builder.withParameter(CommonParameters.PLAYER, player); + if (player != null) builder.withParameter(DirectContextParameters.PLAYER, player); return new ItemBuildContext(player, builder.build()); } @NotNull public static ItemBuildContext of(@Nullable Player player) { if (player == null) return new ItemBuildContext(null, ContextHolder.EMPTY); - return new ItemBuildContext(player, new ContextHolder(Map.of(CommonParameters.PLAYER, () -> player))); + return new ItemBuildContext(player, new ContextHolder(Map.of(DirectContextParameters.PLAYER, () -> player))); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java index eaf7a96ac..19dae5698 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/ExpLootEntryContainer.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -32,8 +32,8 @@ public class ExpLootEntryContainer extends AbstractLootEntryContainer { @Override public boolean expand(LootContext context, Consumer> choiceConsumer) { if (super.test(context)) { - context.getOptionalParameter(CommonParameters.WORLD) - .ifPresent(it -> context.getOptionalParameter(CommonParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); + context.getOptionalParameter(DirectContextParameters.POSITION) + .ifPresent(it -> it.world().dropExp(it, value.getInt(context))); return true; } else { return false; diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java index b16ed84f8..438ef2cd5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/FurnitureItemLootEntryContainer.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.jetbrains.annotations.Nullable; @@ -31,7 +31,7 @@ public class FurnitureItemLootEntryContainer extends SingleItemLootEntryConta @SuppressWarnings("unchecked") @Override protected void createItem(Consumer> lootConsumer, LootContext context) { - Optional> optionalItem = context.getOptionalParameter(CommonParameters.FURNITURE_ITEM); + Optional> optionalItem = context.getOptionalParameter(DirectContextParameters.FURNITURE_ITEM); if (optionalItem.isPresent()) { lootConsumer.accept((Item) optionalItem.get()); } else if (this.hasFallback) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java index 4b5c300f2..4eaffd83c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/SingleItemLootEntryContainer.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -31,7 +31,7 @@ public class SingleItemLootEntryContainer extends AbstractSingleLootEntryCont @SuppressWarnings("unchecked") @Override protected void createItem(Consumer> lootConsumer, LootContext context) { - Item tItem = (Item) CraftEngine.instance().itemManager().createWrappedItem(this.item, context.getOptionalParameter(CommonParameters.PLAYER).orElse(null)); + Item tItem = (Item) CraftEngine.instance().itemManager().createWrappedItem(this.item, context.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null)); if (tItem != null) { lootConsumer.accept(tItem); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index ea6f98583..52a6f8d5e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -31,7 +31,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< @Override protected Item applyInternal(Item item, LootContext context) { - Optional> itemInHand = context.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); + Optional> itemInHand = context.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); int level = itemInHand.map(value -> value.getEnchantment(this.enchantment).map(Enchantment::level).orElse(0)).orElse(0); int newCount = this.formula.apply(item.count(), level); item.count(newCount); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java index 88e9664dc..6fda51f13 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/DropExpFunction.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -26,8 +26,8 @@ public class DropExpFunction extends AbstractLootConditionalFunction { @Override protected Item applyInternal(Item item, LootContext context) { - context.getOptionalParameter(CommonParameters.WORLD) - .ifPresent(it -> context.getOptionalParameter(CommonParameters.LOCATION).ifPresent(loc -> it.dropExp(loc.toCenter(), value.getInt(context)))); + context.getOptionalParameter(DirectContextParameters.POSITION) + .ifPresent(it -> it.world().dropExp(it, value.getInt(context))); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java index 0ab1b6f5e..5f2faa985 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ExplosionDecayFunction.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -22,7 +22,7 @@ public class ExplosionDecayFunction extends AbstractLootConditionalFunction applyInternal(Item item, LootContext context) { - Optional radius = context.getOptionalParameter(CommonParameters.EXPLOSION_RADIUS); + Optional radius = context.getOptionalParameter(DirectContextParameters.EXPLOSION_RADIUS); if (radius.isPresent()) { float f = 1f / radius.get(); int amount = item.count(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java deleted file mode 100644 index 97a3ff9b9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractAdditionalParameterContext.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context; - -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; - -import java.util.List; -import java.util.Optional; - -public abstract class AbstractAdditionalParameterContext extends AbstractCommonContext { - private final List providers; - - public AbstractAdditionalParameterContext(ContextHolder contexts, List providers) { - super(contexts); - this.providers = providers; - } - - public AbstractAdditionalParameterContext(ContextHolder contexts) { - super(contexts); - this.providers = List.of(new CommonParameterProvider()); - } - - @Override - public Optional getOptionalParameter(ContextKey parameter) { - for (LazyContextParameterProvider provider : providers) { - Optional result = provider.getOptionalParameter(parameter); - if (result.isPresent()) { - return result; - } - } - return super.getOptionalParameter(parameter); - } - - @Override - public T getParameterOrThrow(ContextKey parameter) { - for (LazyContextParameterProvider provider : providers) { - Optional result = provider.getOptionalParameter(parameter); - if (result.isPresent()) { - return result.get(); - } - } - return super.getParameterOrThrow(parameter); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java new file mode 100644 index 000000000..b35bed0ee --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.plugin.context.parameter.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractChainParameterContext extends AbstractCommonContext { + private static final Map, ChainParameterProvider> CHAIN_PARAMETERS = new HashMap<>(); + static { + CHAIN_PARAMETERS.put(DirectContextParameters.PLAYER, new PlayerParameterProvider()); + CHAIN_PARAMETERS.put(DirectContextParameters.WORLD, new WorldParameterProvider()); + CHAIN_PARAMETERS.put(DirectContextParameters.BLOCK, new BlockParameterProvider()); + CHAIN_PARAMETERS.put(DirectContextParameters.POSITION, new PositionParameterProvider()); + } + + @SuppressWarnings("unchecked") + private static ChainParameterProvider getParameterProvider(final ContextKey key) { + return (ChainParameterProvider) CHAIN_PARAMETERS.get(key); + } + + public AbstractChainParameterContext(ContextHolder contexts) { + super(contexts); + } + + public AbstractChainParameterContext(ContextHolder contexts, + List additionalParameterProviders) { + super(contexts, additionalParameterProviders); + } + + @Override + public Optional getOptionalParameter(ContextKey parameter) { + ContextKey parentKey = parameter.parent(); + if (parentKey == null) { + return super.getOptionalParameter(parameter); + } + if (!CHAIN_PARAMETERS.containsKey(parentKey)) { + return Optional.empty(); + } + Optional parentValue = getOptionalParameter(parentKey); + if (parentValue.isEmpty()) { + return Optional.empty(); + } + return getParameterProvider(parentKey).getOptionalParameter(parameter, parentValue.get()); + } +} 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 1863c0ab8..83e0853a5 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 @@ -4,14 +4,23 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.plugin.text.minimessage.*; import org.jetbrains.annotations.NotNull; +import java.util.List; import java.util.Optional; public abstract class AbstractCommonContext implements Context { protected final ContextHolder contexts; + protected final List additionalParameterProviders; protected TagResolver[] tagResolvers; public AbstractCommonContext(ContextHolder contexts) { this.contexts = contexts; + this.additionalParameterProviders = List.of(new CommonParameterProvider()); + } + + public AbstractCommonContext(ContextHolder contexts, + List additionalParameterProviders) { + this.contexts = contexts; + this.additionalParameterProviders = additionalParameterProviders; } @Override @@ -31,18 +40,14 @@ public abstract class AbstractCommonContext implements Context { @Override public Optional getOptionalParameter(ContextKey parameter) { + if (!this.additionalParameterProviders.isEmpty()) { + for (AdditionalParameterProvider additionalParameterProvider : additionalParameterProviders) { + Optional optionalValue = additionalParameterProvider.getOptionalParameter(parameter); + if (optionalValue.isPresent()) { + return optionalValue; + } + } + } return this.contexts.getOptional(parameter); } - - @Override - public T getParameterOrThrow(ContextKey parameter) { - return this.contexts.getOrThrow(parameter); - } - - // It's not designed as mutable -// @Override -// public AbstractCommonContext withParameter(ContextKey parameter, T value) { -// this.contexts.withParameter(parameter, value); -// return this; -// } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AdditionalParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AdditionalParameterProvider.java new file mode 100644 index 000000000..db9aa0cde --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AdditionalParameterProvider.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.context; + +import java.util.Optional; + +public interface AdditionalParameterProvider { + + Optional getOptionalParameter(ContextKey parameter); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ChainParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ChainParameterProvider.java new file mode 100644 index 000000000..5c867aac2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ChainParameterProvider.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.context; + +import java.util.Optional; + +public interface ChainParameterProvider { + + Optional getOptionalParameter(ContextKey parameter, A owner); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java similarity index 67% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java index de5df90c1..89af9a7b0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CommonParameterProvider.java @@ -1,7 +1,6 @@ -package net.momirealms.craftengine.core.plugin.context.parameter; +package net.momirealms.craftengine.core.plugin.context; -import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.RandomUtils; import java.util.HashMap; @@ -9,16 +8,16 @@ import java.util.Map; import java.util.Optional; import java.util.function.Function; -public class CommonParameterProvider implements LazyContextParameterProvider { +public class CommonParameterProvider implements AdditionalParameterProvider { private double lastRandom = -1; private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { - CONTEXT_FUNCTIONS.put(CommonParameters.RANDOM, (f) -> { + CONTEXT_FUNCTIONS.put(DirectContextParameters.RANDOM, (f) -> { f.lastRandom = RandomUtils.generateRandomDouble(0,1); return f.lastRandom; }); - CONTEXT_FUNCTIONS.put(CommonParameters.LAST_RANDOM, (f) -> { + CONTEXT_FUNCTIONS.put(DirectContextParameters.LAST_RANDOM, (f) -> { if (f.lastRandom == -1) { f.lastRandom = RandomUtils.generateRandomDouble(0, 1); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java index 989def892..1617c1843 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/Context.java @@ -12,5 +12,7 @@ public interface Context { Optional getOptionalParameter(ContextKey parameter); - T getParameterOrThrow(ContextKey parameter); + default T getParameterOrThrow(ContextKey parameter) { + return getOptionalParameter(parameter).orElseThrow(() -> new RuntimeException("No parameter found for " + parameter)); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java index d184c694e..037b53e39 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java @@ -45,7 +45,7 @@ public class ContextHolder { public T getOrThrow(ContextKey parameter) { Supplier object = (Supplier) this.params.get(parameter); if (object == null) { - throw new NoSuchElementException(parameter.id().toString()); + throw new NoSuchElementException(parameter.node()); } else { return object.get(); } @@ -96,7 +96,7 @@ public class ContextHolder { public T getParameterOrThrow(ContextKey parameter) { Supplier object = (Supplier) this.params.get(parameter); if (object == null) { - throw new NoSuchElementException(parameter.id()); + throw new NoSuchElementException(parameter.node()); } else { return object.get(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java index a33dffffd..4271a7c52 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextKey.java @@ -1,33 +1,77 @@ package net.momirealms.craftengine.core.plugin.context; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class ContextKey { - private final String id; +public interface ContextKey { - public ContextKey(@NotNull String id) { - this.id = id; + static ContextKey direct(@NotNull String node) { + return new Direct<>(node); + } + + static ContextKey chain(@NotNull String node) { + String[] parts = node.split("\\."); + ContextKey current = null; + for (String part : parts) { + current = new Chain<>(part, current); + } + return current; + } + + @Nullable + default ContextKey parent() { + return null; } @NotNull - public String id() { - return id; + String node(); + + record Direct(String node) implements ContextKey { + public Direct(@NotNull String node) { + this.node = node; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ContextKey another)) return false; + return this.node.equals(another.node()); + } + + @Override + public int hashCode() { + return this.node.hashCode(); + } } - @NotNull - public static ContextKey of(@NotNull String id) { - return new ContextKey<>(id); - } + class Chain implements ContextKey { + private final String node; + private final ContextKey parent; - @Override - public final boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ContextKey that)) return false; - return id.equals(that.id); - } + protected Chain(@NotNull String node, @Nullable ContextKey parent) { + this.node = node; + this.parent = parent; + } - @Override - public int hashCode() { - return id.hashCode(); + @Override + public @NotNull String node() { + return this.node; + } + + @SuppressWarnings("unchecked") + @Override + public ContextKey parent() { + return (ContextKey) this.parent; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ContextKey another)) return false; + return this.node.equals(another.node()); + } + + @Override + public int hashCode() { + return this.node.hashCode(); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java deleted file mode 100644 index 0758f7770..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/LazyContextParameterProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context; - -import java.util.Optional; - -public interface LazyContextParameterProvider { - - Optional getOptionalParameter(ContextKey parameter); - - static LazyContextParameterProvider dummy() { - return DummyContextParameterProvider.INSTANCE; - } - - class DummyContextParameterProvider implements LazyContextParameterProvider { - static final DummyContextParameterProvider INSTANCE = new DummyContextParameterProvider(); - - @Override - public Optional getOptionalParameter(ContextKey parameter) { - return Optional.empty(); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java deleted file mode 100644 index bbabeb79a..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerBlockActionContext.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context; - -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.parameter.BlockParameterProvider; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; -import net.momirealms.craftengine.core.world.BlockInWorld; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class PlayerBlockActionContext extends PlayerOptionalContext { - - public PlayerBlockActionContext(@NotNull Player player, @NotNull BlockInWorld block, @NotNull ContextHolder contexts) { - super(player, contexts, List.of(new CommonParameterProvider(), new PlayerParameterProvider(player), new BlockParameterProvider(block))); - } - - public static PlayerBlockActionContext of(@NotNull Player player, @NotNull BlockInWorld block, @NotNull ContextHolder contexts) { - return new PlayerBlockActionContext(player, block, contexts); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java deleted file mode 100644 index 4066c0405..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerFurnitureActionContext.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context; - -import net.momirealms.craftengine.core.entity.furniture.Furniture; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class PlayerFurnitureActionContext extends PlayerOptionalContext { - - public PlayerFurnitureActionContext(@NotNull Player player, @NotNull Furniture furniture, @NotNull ContextHolder contexts) { - super(player, contexts, List.of(new CommonParameterProvider(), new PlayerParameterProvider(player))); - } - - public static PlayerFurnitureActionContext of(@NotNull Player player, @NotNull Furniture furniture, @NotNull ContextHolder contexts) { - return new PlayerFurnitureActionContext(player, furniture, contexts); - } -} 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 ac63f07c9..e71cf975b 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 @@ -2,9 +2,7 @@ package net.momirealms.craftengine.core.plugin.context; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameterProvider; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameterProvider; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.text.minimessage.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,17 +10,20 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -public class PlayerOptionalContext extends AbstractAdditionalParameterContext implements Context { +public class PlayerOptionalContext extends AbstractChainParameterContext implements Context { public static final PlayerOptionalContext EMPTY = new PlayerOptionalContext(null, ContextHolder.EMPTY); protected final Player player; - public PlayerOptionalContext(@Nullable Player player, @NotNull ContextHolder contexts) { - super(contexts, player == null ? List.of(new CommonParameterProvider()) : List.of(new CommonParameterProvider(), new PlayerParameterProvider(player))); + public PlayerOptionalContext(@Nullable Player player, + @NotNull ContextHolder contexts) { + super(contexts); this.player = player; } - public PlayerOptionalContext(@Nullable Player player, @NotNull ContextHolder contexts, @NotNull List providers) { - super(contexts, providers); + public PlayerOptionalContext(@Nullable Player player, + @NotNull ContextHolder contexts, + List additionalParameterProviders) { + super(contexts, additionalParameterProviders); this.player = player; } @@ -33,14 +34,14 @@ public class PlayerOptionalContext extends AbstractAdditionalParameterContext im @NotNull public static PlayerOptionalContext of(@Nullable Player player, @NotNull ContextHolder.Builder contexts) { - if (player != null) contexts.withParameter(CommonParameters.PLAYER, player); + if (player != null) contexts.withParameter(DirectContextParameters.PLAYER, player); return new PlayerOptionalContext(player, contexts.build()); } @NotNull public static PlayerOptionalContext of(@Nullable Player player) { if (player == null) return EMPTY; - return new PlayerOptionalContext(player, new ContextHolder(Map.of(CommonParameters.PLAYER, () -> player))); + return new PlayerOptionalContext(player, new ContextHolder(Map.of(DirectContextParameters.PLAYER, () -> player))); } @Nullable diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java index ce9d60570..15da85637 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.ClickType; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -25,7 +25,7 @@ public class ClickTypeCondition implements Condition { @Override public boolean test(CTX ctx) { - Optional clickTypeOptional = ctx.getOptionalParameter(CommonParameters.CLICK_TYPE); + Optional clickTypeOptional = ctx.getOptionalParameter(DirectContextParameters.CLICK_TYPE); if (clickTypeOptional.isPresent()) { ClickType clickType = clickTypeOptional.get(); return clickType.equals(this.clickType); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 59cc4895d..7c6f06c33 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -18,4 +18,5 @@ public final class CommonConditions { public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key DISTANCE = Key.from("craftengine:distance"); + public static final Key PERMISSION = Key.from("craftengine:permission"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java index 52e22d6a6..24920e9c8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/DistanceCondition.java @@ -5,10 +5,9 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import java.util.Map; import java.util.Optional; @@ -32,14 +31,18 @@ public class DistanceCondition implements Condition { public boolean test(CTX ctx) { float min = this.min.getFloat(ctx); float max = this.max.getFloat(ctx); - Optional optionalPlayer = ctx.getOptionalParameter(CommonParameters.PLAYER); - World world = ctx.getParameterOrThrow(CommonParameters.WORLD); - Vec3d location = ctx.getParameterOrThrow(CommonParameters.LOCATION); + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (optionalPlayer.isEmpty()) { return false; } + Optional optionalPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalPosition.isEmpty()) { + return false; + } + + WorldPosition location = optionalPosition.get(); Player player = optionalPlayer.get(); - if (!player.world().uuid().equals(world.uuid())) { + if (!player.world().uuid().equals(location.world().uuid())) { return false; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java index 3523c9ae4..d9b539a06 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -29,7 +29,7 @@ public class EnchantmentCondition implements Condition @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); if (item.isEmpty()) return false; Optional enchantment = item.get().getEnchantment(id); int level = enchantment.map(Enchantment::level).orElse(0); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java index 1ab5a31b2..be4055055 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/FallingBlockCondition.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import java.util.Map; @@ -16,7 +16,7 @@ public class FallingBlockCondition implements Condition implements ConditionFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java index d33b75f8e..44ae3625b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.Pair; @@ -29,7 +29,7 @@ public class MatchBlockPropertyCondition implements Conditi @Override public boolean test(CTX ctx) { - return ctx.getOptionalParameter(CommonParameters.BLOCK_STATE).map(state -> { + return ctx.getOptionalParameter(DirectContextParameters.BLOCK_STATE).map(state -> { CustomBlock block = state.owner().value(); for (Pair property : this.properties) { Property propertyIns = block.getProperty(property.left()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java index 09951996a..84036263f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -26,7 +26,7 @@ public class MatchItemCondition implements Condition { @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); if (item.isEmpty()) return false; Key key = item.get().id(); String itemId = key.toString(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java index a855b84f9..68b44f5da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/RandomCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -28,12 +28,11 @@ public class RandomCondition implements Condition { @Override public boolean test(CTX ctx) { if (this.previous) { - // TODO This might produce bugs if the context doesn't use a common provider - Optional random = ctx.getOptionalParameter(CommonParameters.LAST_RANDOM); + Optional random = ctx.getOptionalParameter(DirectContextParameters.LAST_RANDOM); return random.map(d -> d < this.chance.getFloat(ctx)) .orElseGet(() -> RandomUtils.generateRandomFloat(0, 1) < this.chance.getFloat(ctx)); } else { - Optional random = ctx.getOptionalParameter(CommonParameters.RANDOM); + Optional random = ctx.getOptionalParameter(DirectContextParameters.RANDOM); return random.map(d -> d < this.chance.getFloat(ctx)) .orElseGet(() -> RandomUtils.generateRandomFloat(0, 1) < this.chance.getFloat(ctx)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java index 385bb708f..ca2713f75 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/SurvivesExplosionCondition.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -18,7 +18,7 @@ public class SurvivesExplosionCondition implements Conditio @Override public boolean test(CTX ctx) { - Optional radius = ctx.getOptionalParameter(CommonParameters.EXPLOSION_RADIUS); + Optional radius = ctx.getOptionalParameter(DirectContextParameters.EXPLOSION_RADIUS); if (radius.isPresent()) { float f = 1f / radius.get(); return RandomUtils.generateRandomFloat(0, 1) < f; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java index fb0870344..e73652cca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.PlayerParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -31,7 +31,7 @@ public class TableBonusCondition implements Condition @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(PlayerParameters.MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); int level = item.map(value -> value.getEnchantment(this.enchantmentType).map(Enchantment::level).orElse(0)).orElse(0); float f = this.values.get(Math.min(level, this.values.size() - 1)); return RandomUtils.generateRandomFloat(0, 1) < f; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index 1dc91d843..98c69097e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Platform; import net.momirealms.craftengine.core.plugin.context.*; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.plugin.context.text.TextProvider; @@ -33,7 +33,7 @@ public class CommandFunction extends AbstractConditionalFun @Override public void runInternal(CTX ctx) { if (this.asPlayer) { - Optional owner = ctx.getOptionalParameter(CommonParameters.PLAYER); + Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { owner.ifPresent(it -> { for (TextProvider c : this.command) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 574ad1ba0..ed0bd1e32 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -2,7 +2,22 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.util.Key; -public class CommonFunctions { - public static final Key COMMAND = Key.of("craftengine:command"); +public final class CommonFunctions { + private CommonFunctions() {} + public static final Key RUN_ALL = Key.of("craftengine:run_all"); + public static final Key COMMAND = Key.of("craftengine:command"); + public static final Key MESSAGE = Key.of("craftengine:message"); + public static final Key ACTIONBAR = Key.of("craftengine:actionbar"); + public static final Key TITLE = Key.of("craftengine:title"); + public static final Key PARTICLE = Key.of("craftengine:particle"); + public static final Key SOUND = Key.of("craftengine:sound"); + public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect"); + public static final Key BREAK_BLOCK = Key.of("craftengine:break_block"); + public static final Key CANCEL_EVENT = Key.of("craftengine:cancel_event"); + public static final Key FOOD = Key.of("craftengine:food"); + public static final Key SATURATION = Key.of("craftengine:saturation"); + public static final Key MONEY = Key.of("craftengine:money"); + public static final Key OXYGEN = Key.of("craftengine:oxygen"); + public static final Key MINE_RADIUS = Key.of("craftengine:mine_radius"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java new file mode 100644 index 000000000..541774050 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -0,0 +1,70 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class MessageFunction extends AbstractConditionalFunction { + private final List messages; + private final PlayerSelector selector; + private final boolean overlay; + + public MessageFunction(List> predicates, List messages, @Nullable PlayerSelector selector, boolean overlay) { + super(predicates); + this.messages = messages; + this.selector = selector; + this.overlay = overlay; + } + + @Override + public void runInternal(CTX ctx) { + Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + if (this.selector == null) { + owner.ifPresent(it -> { + for (TextProvider c : this.messages) { + it.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(ctx), ctx.tagResolvers()), this.overlay); + } + }); + } else { + for (Player viewer : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY)); + for (TextProvider c : this.messages) { + viewer.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(relationalContext), relationalContext.tagResolvers()), this.overlay); + } + } + } + } + + @Override + public Key type() { + return CommonFunctions.MESSAGE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object message = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "messages", "message"), "warning.config.function.command.missing_message"); + List messages = MiscUtils.getAsStringList(message).stream().map(TextProviders::fromString).toList(); + boolean overlay = (boolean) arguments.getOrDefault("overlay", false); + return new MessageFunction<>(getPredicates(arguments), messages, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), overlay); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java index 50107633d..e707aca80 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java @@ -1,39 +1,32 @@ package net.momirealms.craftengine.core.plugin.context.parameter; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; import net.momirealms.craftengine.core.world.BlockInWorld; -import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; -public class BlockParameterProvider implements LazyContextParameterProvider { +public class BlockParameterProvider implements ChainParameterProvider { private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { - CONTEXT_FUNCTIONS.put(BlockParameters.X, BlockInWorld::x); - CONTEXT_FUNCTIONS.put(BlockParameters.Y, BlockInWorld::y); - CONTEXT_FUNCTIONS.put(BlockParameters.Z, BlockInWorld::z); - CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_X, BlockInWorld::x); - CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_Y, BlockInWorld::y); - CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_Z, BlockInWorld::z); - CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_OWNER, BlockInWorld::owner); - CONTEXT_FUNCTIONS.put(BlockParameters.BLOCK_STATE, BlockInWorld::getAsString); - CONTEXT_FUNCTIONS.put(BlockParameters.WORLD_NAME, b -> b.world().name()); - } - - private final BlockInWorld block; - - public BlockParameterProvider(@NotNull BlockInWorld block) { - this.block = Objects.requireNonNull(block); + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, BlockInWorld::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, BlockInWorld::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, BlockInWorld::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, BlockInWorld::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, BlockInWorld::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, BlockInWorld::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.CUSTOM_BLOCK, BlockInWorld::customBlock); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_STATE, BlockInWorld::customBlockState); + CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, BlockInWorld::world); + CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, BlockInWorld::position); } @SuppressWarnings("unchecked") @Override - public Optional getOptionalParameter(ContextKey parameter) { - return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(this.block)); + public Optional getOptionalParameter(ContextKey parameter, BlockInWorld block) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(block)); } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java deleted file mode 100644 index 68d2988b8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameters.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context.parameter; - -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.Key; - -public final class BlockParameters { - private BlockParameters() {} - - public static final ContextKey X = ContextKey.of("block.x"); - public static final ContextKey Y = ContextKey.of("block.y"); - public static final ContextKey Z = ContextKey.of("block.z"); - public static final ContextKey BLOCK_X = ContextKey.of("block.block_x"); - public static final ContextKey BLOCK_Y = ContextKey.of("block.block_y"); - public static final ContextKey BLOCK_Z = ContextKey.of("block.block_z"); - public static final ContextKey BLOCK_STATE = ContextKey.of("block.state"); - public static final ContextKey BLOCK_OWNER = ContextKey.of("block.owner.id"); - public static final ContextKey WORLD_NAME = ContextKey.of("block.world.name"); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java new file mode 100644 index 000000000..03f350952 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ContextKey; + +public final class ChainContextParameters { + private ChainContextParameters() {} + + public static final ContextKey> PLAYER_MAIN_HAND_ITEM = ContextKey.chain("player.main_hand_item"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java deleted file mode 100644 index 2b2ad13c9..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/CommonParameters.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context.parameter; - -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.ClickType; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.World; - -public final class CommonParameters { - private CommonParameters() {} - - public static final ContextKey RANDOM = ContextKey.of("random"); - public static final ContextKey LAST_RANDOM = ContextKey.of("last_random"); - public static final ContextKey LOCATION = ContextKey.of("location"); - public static final ContextKey WORLD = ContextKey.of("world"); - public static final ContextKey> FURNITURE_ITEM = ContextKey.of("furniture_item"); - public static final ContextKey FALLING_BLOCK = ContextKey.of("falling_block"); - public static final ContextKey EXPLOSION_RADIUS = ContextKey.of("explosion_radius"); - public static final ContextKey PLAYER = ContextKey.of("player"); - public static final ContextKey CLICK_TYPE = ContextKey.of("click_type"); - public static final ContextKey BLOCK_STATE = ContextKey.of("block_state"); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java new file mode 100644 index 000000000..6bfc4237e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.world.*; + +import java.util.UUID; + +public final class DirectContextParameters { + private DirectContextParameters() {} + + public static final ContextKey RANDOM = ContextKey.direct("random"); + public static final ContextKey LAST_RANDOM = ContextKey.direct("last_random"); + public static final ContextKey WORLD = ContextKey.direct("world"); + public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); + public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); + public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); + public static final ContextKey PLAYER = ContextKey.direct("player"); + public static final ContextKey CLICK_TYPE = ContextKey.direct("click_type"); + public static final ContextKey BLOCK_STATE = ContextKey.direct("custom_block_state"); + public static final ContextKey COORDINATE = ContextKey.direct("coordinate"); + public static final ContextKey POSITION = ContextKey.direct("position"); + public static final ContextKey NAME = ContextKey.direct("name"); + public static final ContextKey X = ContextKey.direct("x"); + public static final ContextKey Y = ContextKey.direct("y"); + public static final ContextKey Z = ContextKey.direct("z"); + public static final ContextKey BLOCK_X = ContextKey.direct("block_x"); + public static final ContextKey BLOCK_Y = ContextKey.direct("block_y"); + public static final ContextKey BLOCK_Z = ContextKey.direct("block_z"); + public static final ContextKey UUID = ContextKey.direct("uuid"); + public static final ContextKey> MAIN_HAND_ITEM = ContextKey.direct("main_hand_item"); + public static final ContextKey> OFF_HAND_ITEM = ContextKey.direct("off_hand_item"); + public static final ContextKey CUSTOM_BLOCK = ContextKey.direct("custom_block"); + public static final ContextKey BLOCK = ContextKey.direct("block"); + public static final ContextKey TIME = ContextKey.direct("time"); + public static final ContextKey FURNITURE = ContextKey.direct("furniture"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java index 4e7efd8e3..efeca907e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -1,45 +1,38 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.entity.AbstractEntity; +import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.plugin.context.LazyContextParameterProvider; import net.momirealms.craftengine.core.util.MCUtils; -import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; -public class PlayerParameterProvider implements LazyContextParameterProvider { +public class PlayerParameterProvider implements ChainParameterProvider { private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { - CONTEXT_FUNCTIONS.put(PlayerParameters.X, AbstractEntity::x); - CONTEXT_FUNCTIONS.put(PlayerParameters.Y, AbstractEntity::y); - CONTEXT_FUNCTIONS.put(PlayerParameters.Z, AbstractEntity::z); - CONTEXT_FUNCTIONS.put(PlayerParameters.POS, AbstractEntity::position); - CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); - CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); - CONTEXT_FUNCTIONS.put(PlayerParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); - CONTEXT_FUNCTIONS.put(PlayerParameters.NAME, Player::name); - CONTEXT_FUNCTIONS.put(PlayerParameters.UUID, Player::uuid); - CONTEXT_FUNCTIONS.put(PlayerParameters.WORLD_NAME, p -> p.world().name()); - CONTEXT_FUNCTIONS.put(PlayerParameters.MAIN_HAND_ITEM, p -> p.getItemInHand(InteractionHand.MAIN_HAND)); - CONTEXT_FUNCTIONS.put(PlayerParameters.OFF_HAND_ITEM, p -> p.getItemInHand(InteractionHand.OFF_HAND)); - } - - private final Player player; - - public PlayerParameterProvider(@NotNull Player player) { - this.player = Objects.requireNonNull(player); + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, AbstractEntity::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, AbstractEntity::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, AbstractEntity::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, AbstractEntity::position); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name); + CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Player::uuid); + CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world); + CONTEXT_FUNCTIONS.put(DirectContextParameters.MAIN_HAND_ITEM, p -> p.getItemInHand(InteractionHand.MAIN_HAND)); + CONTEXT_FUNCTIONS.put(DirectContextParameters.OFF_HAND_ITEM, p -> p.getItemInHand(InteractionHand.OFF_HAND)); } @SuppressWarnings("unchecked") @Override - public Optional getOptionalParameter(ContextKey parameter) { - return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(this.player)); + public Optional getOptionalParameter(ContextKey parameter, Player player) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(player)); } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java deleted file mode 100644 index 4d558ba1b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameters.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context.parameter; - -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.world.Vec3d; - -import java.util.UUID; - -public final class PlayerParameters { - private PlayerParameters() {} - - public static final ContextKey X = ContextKey.of("player.x"); - public static final ContextKey Y = ContextKey.of("player.y"); - public static final ContextKey Z = ContextKey.of("player.z"); - public static final ContextKey POS = ContextKey.of("player.pos"); - public static final ContextKey BLOCK_X = ContextKey.of("player.block_x"); - public static final ContextKey BLOCK_Y = ContextKey.of("player.block_y"); - public static final ContextKey BLOCK_Z = ContextKey.of("player.block_z"); - public static final ContextKey NAME = ContextKey.of("player.name"); - public static final ContextKey WORLD_NAME = ContextKey.of("player.world.name"); - public static final ContextKey UUID = ContextKey.of("player.uuid"); - public static final ContextKey> MAIN_HAND_ITEM = ContextKey.of("player.main_hand"); - public static final ContextKey> OFF_HAND_ITEM = ContextKey.of("player.off_hand"); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java new file mode 100644 index 000000000..710917c19 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class PositionParameterProvider implements ChainParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, WorldPosition::world); + CONTEXT_FUNCTIONS.put(DirectContextParameters.COORDINATE, p -> p); + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, WorldPosition::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, WorldPosition::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, WorldPosition::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, WorldPosition position) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(position)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java new file mode 100644 index 000000000..cacf39e98 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java @@ -0,0 +1,24 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.world.World; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class WorldParameterProvider implements ChainParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, World::name); + CONTEXT_FUNCTIONS.put(DirectContextParameters.TIME, World::time); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, World world) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(world)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java index 19330e03e..5b075bd98 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MCUtils; @@ -35,8 +35,7 @@ public class AllPlayerSelector implements PlayerSelector players = new ArrayList<>(); for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { PlayerOptionalContext newContext = PlayerOptionalContext.of(player, ContextHolder.builder() - .withOptionalParameter(CommonParameters.WORLD, context.getOptionalParameter(CommonParameters.WORLD).orElse(null)) - .withOptionalParameter(CommonParameters.LOCATION, context.getOptionalParameter(CommonParameters.LOCATION).orElse(null)) + .withOptionalParameter(DirectContextParameters.POSITION, context.getOptionalParameter(DirectContextParameters.POSITION).orElse(null)) ); if (!this.predicate.test((CTX) newContext)) { continue; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java index ea749f3ba..978c8ccfd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.selector; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.CommonParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import java.util.List; @@ -11,7 +11,7 @@ public class SelfPlayerSelector implements PlayerSelector get(CTX context) { - return List.of(context.getParameterOrThrow(CommonParameters.PLAYER)); + return List.of(context.getParameterOrThrow(DirectContextParameters.PLAYER)); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java index 6acee5ff4..146afc563 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.plugin.event; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -31,23 +31,23 @@ public class BlockEventConditions { register(CommonConditions.CLICK_TYPE, new ClickTypeCondition.FactoryImpl<>()); } - public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY) + public static void register(Key key, ConditionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY) .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_CONDITION_FACTORY.location(), key)); holder.bindValue(factory); } - public static Condition fromMap(Map map) { + public static Condition fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.event.condition.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); if (key.value().charAt(0) == '!') { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); } return new InvertedCondition<>(factory.create(map)); } else { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); + ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java index 0cce7cdf1..21f735b3c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.plugin.event; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -22,16 +22,16 @@ public class BlockEventFunctions { register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(BlockEventConditions::fromMap)); } - public static void register(Key key, FunctionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) + public static void register(Key key, FunctionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_FUNCTION_FACTORY.location(), key)); holder.bindValue(factory); } - public static Function fromMap(Map map) { + public static Function fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "TODO I18N"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - FunctionFactory factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); + FunctionFactory factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); if (factory == null) { throw new LocalizedResourceConfigException("TODO I18N", type); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java index 946cbf505..dddb42e5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiParameters.java @@ -2,9 +2,11 @@ package net.momirealms.craftengine.core.plugin.gui; import net.momirealms.craftengine.core.plugin.context.ContextKey; -public class GuiParameters { - public static final ContextKey MAX_PAGE = ContextKey.of("max_page"); - public static final ContextKey CURRENT_PAGE = ContextKey.of("current_page"); - public static final ContextKey COOKING_TIME = ContextKey.of("cooking_time"); - public static final ContextKey COOKING_EXPERIENCE = ContextKey.of("cooking_experience"); +public final class GuiParameters { + private GuiParameters() {} + + public static final ContextKey MAX_PAGE = ContextKey.direct("max_page"); + public static final ContextKey CURRENT_PAGE = ContextKey.direct("current_page"); + public static final ContextKey COOKING_TIME = ContextKey.direct("cooking_time"); + public static final ContextKey COOKING_EXPERIENCE = ContextKey.direct("cooking_experience"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java index 595be9c85..0b775e569 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java @@ -25,7 +25,7 @@ public class NamedArgumentTag implements TagResolver { if (!has(name)) { return null; } - ContextKey key = ContextKey.of(arguments.popOr("No argument key provided").toString()); + ContextKey key = ContextKey.chain(arguments.popOr("No argument key provided").toString()); Optional optional = this.context.getOptionalParameter(key); Object value = optional.orElse(null); if (value == null) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 63e13ac40..70a3666b1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -21,7 +21,7 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; @@ -52,8 +52,8 @@ public class BuiltInRegistries { public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); - public static final Registry> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); - public static final Registry> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); + public static final Registry> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); + public static final Registry> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index a5bd19c5d..e8b6abaeb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -21,7 +21,7 @@ import net.momirealms.craftengine.core.pack.model.select.SelectPropertyFactory; import net.momirealms.craftengine.core.pack.model.special.SpecialModelFactory; import net.momirealms.craftengine.core.pack.model.tint.TintFactory; import net.momirealms.craftengine.core.plugin.config.template.TemplateArgumentFactory; -import net.momirealms.craftengine.core.plugin.context.PlayerBlockActionContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; @@ -53,6 +53,6 @@ public class Registries { public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); - public static final ResourceKey>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); + public static final ResourceKey>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); + public static final ResourceKey>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java index 461ef2699..5dac8cf13 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockInWorld.java @@ -1,7 +1,9 @@ package net.momirealms.craftengine.core.world; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; -import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; public interface BlockInWorld { @@ -13,9 +15,15 @@ public interface BlockInWorld { return false; } - Key owner(); + @Nullable + CustomBlock customBlock(); - String getAsString(); + @Nullable + ImmutableBlockState customBlockState(); + + default WorldPosition position() { + return new WorldPosition(world(), x(), y(), z()); + } World world(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 5817a5e1f..565d93067 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -27,13 +27,15 @@ public interface World { UUID uuid(); - void dropItemNaturally(Vec3d location, Item item); + void dropItemNaturally(Position location, Item item); - void dropExp(Vec3d location, int amount); + void dropExp(Position location, int amount); - void playBlockSound(Vec3d location, Key sound, float volume, float pitch); + void playBlockSound(Position location, Key sound, float volume, float pitch); - default void playBlockSound(Vec3d location, SoundData data) { + default void playBlockSound(Position location, SoundData data) { playBlockSound(location, data.id(), data.volume(), data.pitch()); } + + long time(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java index f4024f04c..868538ea6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldPosition.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.world; -public class WorldPosition { +public class WorldPosition implements Position { private final World world; private final double x; private final double y; @@ -8,6 +8,15 @@ public class WorldPosition { private final float xRot; private final float yRot; + public WorldPosition(World world, Position position) { + this.x = position.x(); + this.y = position.y(); + this.z = position.z(); + this.world = world; + this.xRot = 0f; + this.yRot = 0f; + } + public WorldPosition(World world, Position position, float xRot, float yRot) { this.x = position.x(); this.y = position.y(); @@ -17,6 +26,15 @@ public class WorldPosition { this.yRot = yRot; } + public WorldPosition(World world, double x, double y, double z) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.xRot = 0f; + this.yRot = 0f; + } + public WorldPosition(World world, double x, double y, double z, float xRot, float yRot) { this.world = world; this.x = x; @@ -26,14 +44,17 @@ public class WorldPosition { this.yRot = yRot; } + @Override public double x() { return x; } + @Override public double y() { return y; } + @Override public double z() { return z; } diff --git a/gradle.properties b/gradle.properties index ec72047d6..0a6c0a56e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.21 +nms_helper_version=0.65.22 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 60e4db7a9af1d46e37768c77dc3e53f65e526831 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 14 May 2025 15:54:02 +0800 Subject: [PATCH 60/73] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 10 +- .../src/main/resources/translations/zh_cn.yml | 12 ++- .../bukkit/block/BlockEventListener.java | 10 ++ .../bukkit/block/BukkitBlockManager.java | 53 +-------- .../furniture/BukkitFurnitureManager.java | 8 +- .../bukkit/item/BukkitCustomItem.java | 28 ++++- .../bukkit/item/BukkitItemManager.java | 2 + .../factory/ComponentItemFactory1_20_5.java | 16 +-- .../item/listener/ItemEventListener.java | 102 +++++++++++++----- .../plugin/network/PacketConsumers.java | 28 ++++- .../entity/furniture/CustomFurniture.java | 14 +++ .../craftengine/core/item/CustomItem.java | 10 +- .../AbstractChainParameterContext.java | 6 ++ .../parameter/DirectContextParameters.java | 9 ++ .../parameter/ItemParameterProvider.java | 25 +++++ .../parameter/WorldParameterProvider.java | 1 + .../plugin/event/BlockEventFunctions.java | 40 ------- ...ntConditions.java => EventConditions.java} | 22 ++-- .../core/plugin/event/EventFunctions.java | 101 +++++++++++++++++ .../core/plugin/event/EventTrigger.java | 3 +- .../core/registry/BuiltInRegistries.java | 4 +- .../craftengine/core/registry/Registries.java | 4 +- gradle.properties | 2 +- 23 files changed, 353 insertions(+), 157 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/event/{BlockEventConditions.java => EventConditions.java} (81%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 456d2405d..e8dca66a7 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -225,8 +225,6 @@ warning.config.block.behavior.leaves.missing_distance: "Issue found in f warning.config.block.behavior.sapling.missing_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." warning.config.block.behavior.sapling.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." warning.config.block.behavior.strippable.missing_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." -warning.config.block.event.condition.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for event condition." -warning.config.block.event.condition.invalid_type: "Issue found in file - The block '' is using an invalid 'type' argument '' for event condition." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" @@ -298,6 +296,10 @@ warning.config.conflict_matcher.all_of.missing_terms: "Issue found in co warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." -warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." \ No newline at end of file +warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." +warning.config.event.condition.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for event condition." +warning.config.event.condition.invalid_type: "Issue found in file - The config '' is using an invalid 'type' argument '' for event condition." +warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." +warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 9a75a659e..a8c511c27 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -90,6 +90,7 @@ warning.config.condition.match_block_property.missing_properties: "在 warning.config.condition.match_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'match_item' 条件所需的 'id' 参数" warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" +warning.config.condition.click_type.missing_click_type: "Issue found in file - The config '' is missing the required 'click-type' argument for 'click_type' condition." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" @@ -224,8 +225,6 @@ warning.config.block.behavior.leaves.missing_distance: "在文件 在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'stage' 属性" warning.config.block.behavior.sapling.missing_feature: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.strippable.missing_stripped: "在文件 发现问题 - 方块 '' 的 'strippable_block' 行为缺少必需的 'stripped' 参数" -warning.config.block.event.condition.missing_type: "在文件 - 方块 '' 的事件条件缺少 'type' 参数" -warning.config.block.event.condition.invalid_type: "在文件 - 方块 '' 使用了无效的事件条件类型 ''" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" @@ -296,4 +295,11 @@ warning.config.conflict_matcher.inverted.missing_term: "在 config.yml warning.config.conflict_matcher.all_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 全匹配器缺少必需的 'terms' 参数" warning.config.conflict_matcher.any_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 任一匹配器缺少必需的 'terms' 参数" warning.config.conflict_resolution.missing_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案缺少必需的 'type' 参数" -warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" +warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." +warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." +warning.config.event.condition.missing_type: "在文件 - 配置项 '' 的事件条件缺少 'type' 参数" +warning.config.event.condition.invalid_type: "在文件 - 配置项 '' 使用了无效的事件条件类型 ''" +warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." +warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 013583c6d..f8fa97ab0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; @@ -14,7 +15,9 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; @@ -136,7 +139,13 @@ public class BlockEventListener implements Listener { return; } + // execute functions net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withParameter(DirectContextParameters.BLOCK_STATE, state)); + state.owner().value().execute(context, EventTrigger.BREAK); + // handle waterlogged blocks @SuppressWarnings("unchecked") Property waterloggedProperty = (Property) state.owner().value().getProperty("waterlogged"); @@ -146,6 +155,7 @@ public class BlockEventListener implements Listener { location.getWorld().setBlockData(location, Material.WATER.createBlockData()); } } + // play sound WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); world.playBlockSound(position, state.sounds().breakSound()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 0fa67030c..7d77e45fe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.BlockEventFunctions; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; @@ -459,7 +459,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } Object eventsObj = ResourceConfigUtils.get(section, "events", "event"); - EnumMap>> events = parseEvents(eventsObj); + EnumMap>> events = EventFunctions.parseEvents(eventsObj); Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) @@ -513,55 +513,6 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private EnumMap>> parseEvents(Object eventsObj) { - EnumMap>> events = new EnumMap<>(EventTrigger.class); - if (eventsObj instanceof Map eventsSection) { - Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); - for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { - try { - EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); - if (eventEntry.getValue() instanceof List list) { - if (list.size() == 1) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); - } else if (list.size() == 2) { - events.put(eventTrigger, List.of( - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) - )); - } else { - List> eventsList = new ArrayList<>(); - for (Object event : list) { - eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); - } - events.put(eventTrigger, eventsList); - } - } else if (eventEntry.getValue() instanceof Map eventSection) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); - } - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); - } - } - } else if (eventsObj instanceof List list) { - @SuppressWarnings("unchecked") - List> eventsList = (List>) list; - for (Map eventSection : eventsList) { - Object onObj = eventSection.get("on"); - if (onObj == null) { - throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); - } - try { - EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); - Function function = BlockEventFunctions.fromMap(eventSection); - events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); - } - } - } - return events; - } - private Map> parseProperties(Map propertiesSection) { Map> properties = new HashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { 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 38329375e..5d35be647 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 @@ -16,10 +16,15 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; @@ -212,7 +217,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { // get loot table LootTable lootTable = lootMap == null ? null : LootTable.fromMap(lootMap); - CustomFurniture furniture = new CustomFurniture(id, settings, placements, lootTable); + EnumMap>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + CustomFurniture furniture = new CustomFurniture(id, settings, placements, events, lootTable); byId.put(id, furniture); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 93e2ad6db..f3ac95c70 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -6,14 +6,15 @@ import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; public class BukkitCustomItem implements CustomItem { private final Key id; @@ -26,6 +27,7 @@ public class BukkitCustomItem implements CustomItem { private final NetworkItemDataProcessor[] networkItemDataProcessors; private final List behaviors; private final ItemSettings settings; + private final EnumMap>> events; @SuppressWarnings("unchecked") public BukkitCustomItem(Key id, @@ -34,10 +36,12 @@ public class BukkitCustomItem implements CustomItem { List> modifiers, List> clientBoundModifiers, List behaviors, - ItemSettings settings) { + ItemSettings settings, + EnumMap>> events) { this.id = id; this.material = material; this.materialKey = materialKey; + this.events = events; // unchecked cast this.modifiers = modifiers.toArray(new ItemDataModifier[0]); // unchecked cast @@ -65,6 +69,13 @@ public class BukkitCustomItem implements CustomItem { this.networkItemDataProcessors = networkItemDataProcessors.toArray(new NetworkItemDataProcessor[0]); } + @Override + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + @Override public Key id() { return this.id; @@ -145,6 +156,7 @@ public class BukkitCustomItem implements CustomItem { private Material material; private Key materialKey; private ItemSettings settings; + private EnumMap>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(); private final List> modifiers = new ArrayList<>(); private final List> clientBoundModifiers = new ArrayList<>(); @@ -204,10 +216,16 @@ public class BukkitCustomItem implements CustomItem { return this; } + @Override + public Builder events(EnumMap>> events) { + this.events = events; + return this; + } + @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings); + return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings, this.events); } } } 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 89798dd29..c4d9295ab 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 @@ -33,6 +33,7 @@ import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectPrope import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -357,6 +358,7 @@ public class BukkitItemManager extends AbstractItemManager { itemSettings.canPlaceRelatedVanillaBlock(true); } itemBuilder.settings(itemSettings); + itemBuilder.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))); CustomItem customItem = itemBuilder.build(); customItems.put(id, customItem); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 2cf775754..9261ae98d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -247,12 +247,16 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory dyedColor(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.DYED_COLOR)) return Optional.empty(); - return Optional.ofNullable( - (Integer) ComponentType.encodeJava( - ComponentTypes.DYED_COLOR, - item.getComponent(ComponentTypes.DYED_COLOR) - ).orElse(null) - ); + Object javaObj = ComponentType.encodeJava( + ComponentTypes.DYED_COLOR, + item.getComponent(ComponentTypes.DYED_COLOR) + ).orElse(null); + if (javaObj instanceof Integer integer) { + return Optional.of(integer); + } else if (javaObj instanceof Map map) { + return Optional.of((int) map.get("rgb")); + } + return Optional.empty(); } @Override 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 424c35b6a..95f404fef 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 @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.context.CommonParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; @@ -33,6 +34,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -97,11 +99,10 @@ public class ItemEventListener implements Listener { // run custom functions CustomBlock customBlock = immutableBlockState.owner().value(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.PLAYER, serverPlayer) .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) - .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT) - .build()); + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); customBlock.execute(context, EventTrigger.CLICK); if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); else customBlock.execute(context, EventTrigger.LEFT_CLICK); @@ -156,6 +157,18 @@ public class ItemEventListener implements Listener { } } + // execute item functions + if (hasCustomItem) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } + // 检查其他的物品行为,物品行为理论只在交互时处理 Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); // 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为 @@ -181,42 +194,83 @@ public class ItemEventListener implements Listener { } } } + + if (hasCustomItem && action == Action.LEFT_CLICK_BLOCK) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + customItem.execute(context, EventTrigger.LEFT_CLICK); + } } @EventHandler public void onInteractAir(PlayerInteractEvent event) { - if (event.getAction() != Action.RIGHT_CLICK_AIR) + Action action = event.getAction(); + if (action != Action.RIGHT_CLICK_AIR && action != Action.LEFT_CLICK_AIR) return; - Player bukkitPlayer = event.getPlayer(); - BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer); - InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - if (cancelEventIfHasInteraction(event, player, hand)) { + Player player = event.getPlayer(); + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + if (serverPlayer.isSpectatorMode()) return; - } - if (player.isSpectatorMode()) { - return; - } - // Gets the item in hand - Item itemInHand = player.getItemInHand(hand); + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + Item itemInHand = serverPlayer.getItemInHand(hand); // should never be null if (itemInHand == null) return; - Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); - if (optionalItemBehaviors.isPresent()) { - for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { - InteractionResult result = itemBehavior.use(player.world(), player, hand); - if (result == InteractionResult.SUCCESS_AND_CANCEL) { - event.setCancelled(true); - return; - } - if (result != InteractionResult.PASS) { - return; + if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { + return; + } + + Optional> optionalCustomItem = itemInHand.getCustomItem(); + if (optionalCustomItem.isPresent()) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + if (action.isRightClick()) customItem.execute(context, EventTrigger.RIGHT_CLICK); + else customItem.execute(context, EventTrigger.LEFT_CLICK); + } + + if (action.isRightClick()) { + Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); + if (optionalItemBehaviors.isPresent()) { + for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { + InteractionResult result = itemBehavior.use(serverPlayer.world(), serverPlayer, hand); + if (result == InteractionResult.SUCCESS_AND_CANCEL) { + event.setCancelled(true); + return; + } + if (result != InteractionResult.PASS) { + return; + } } } } } + @EventHandler(ignoreCancelled = true) + public void onConsumeItem(PlayerItemConsumeEvent event) { + ItemStack consumedItem = event.getItem(); + if (ItemUtils.isEmpty(consumedItem)) return; + Item wrapped = this.plugin.itemManager().wrap(consumedItem); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + return; + } + CustomItem customItem = optionalCustomItem.get(); + PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() + .withParameter(DirectContextParameters.CONSUMED_ITEM, wrapped) + .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) + ); + customItem.execute(context, EventTrigger.CONSUME); + } + private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { if (hand == InteractionHand.OFF_HAND) { int currentTicks = player.gameTicks(); 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 cec73f88d..d0326c8cc 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 @@ -33,12 +33,13 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.BlockHitResult; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.EntityHitResult; -import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; @@ -46,6 +47,7 @@ import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; @@ -1688,6 +1690,16 @@ public class PacketConsumers { if (EventUtils.fireAndCheckCancel(breakEvent)) { return; } + + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); } } else if (actionType == Reflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) { @@ -1710,6 +1722,14 @@ public class PacketConsumers { return; } + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); + furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + furniture.config().execute(context, EventTrigger.CLICK); + if (player.isSneaking()) { // try placing another furniture above it AABB hitBox = furniture.aabbByEntityId(entityId); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index cbf5f12c9..8d2d93885 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -1,12 +1,17 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; +import java.util.Collections; import java.util.EnumMap; +import java.util.List; import java.util.Optional; public class CustomFurniture { @@ -14,20 +19,29 @@ public class CustomFurniture { private final FurnitureSettings settings; private final EnumMap placements; private final AnchorType anyType; + private final EnumMap>> events; @Nullable private final LootTable lootTable; public CustomFurniture(@NotNull Key id, @NotNull FurnitureSettings settings, @NotNull EnumMap placements, + @NotNull EnumMap>> events, @Nullable LootTable lootTable) { this.id = id; this.settings = settings; this.placements = placements; this.lootTable = lootTable; + this.events = events; this.anyType = placements.keySet().stream().findFirst().orElse(null); } + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + public Key id() { return id; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index b4ff58f2a..b30c543a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -3,11 +3,13 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.Map; +import java.util.*; public interface CustomItem extends BuildableItem { @@ -39,6 +41,8 @@ public interface CustomItem extends BuildableItem { Item buildItem(ItemBuildContext context); + void execute(PlayerOptionalContext context, EventTrigger trigger); + @NotNull List behaviors(); @@ -61,6 +65,8 @@ public interface CustomItem extends BuildableItem { Builder settings(ItemSettings settings); + Builder events(EnumMap>> events); + CustomItem build(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index b35bed0ee..fc9b57f60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -14,6 +14,12 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.WORLD, new WorldParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.BLOCK, new BlockParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.POSITION, new PositionParameterProvider()); + ItemParameterProvider itemProvider = new ItemParameterProvider(); + CHAIN_PARAMETERS.put(DirectContextParameters.MAIN_HAND_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.CONSUMED_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.TOOL, itemProvider); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 6bfc4237e..0d930d0f9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -2,11 +2,14 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.*; import java.util.UUID; @@ -18,6 +21,8 @@ public final class DirectContextParameters { public static final ContextKey LAST_RANDOM = ContextKey.direct("last_random"); public static final ContextKey WORLD = ContextKey.direct("world"); public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); + public static final ContextKey> CONSUMED_ITEM = ContextKey.direct("consumed_item"); + public static final ContextKey> TOOL = ContextKey.direct("tool"); public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); public static final ContextKey PLAYER = ContextKey.direct("player"); @@ -38,5 +43,9 @@ public final class DirectContextParameters { public static final ContextKey CUSTOM_BLOCK = ContextKey.direct("custom_block"); public static final ContextKey BLOCK = ContextKey.direct("block"); public static final ContextKey TIME = ContextKey.direct("time"); + public static final ContextKey ID = ContextKey.direct("id"); + public static final ContextKey CUSTOM_MODEL_DATA = ContextKey.direct("custom_model_data"); public static final ContextKey FURNITURE = ContextKey.direct("furniture"); + public static final ContextKey ANCHOR_TYPE = ContextKey.direct("anchor_type"); + public static final ContextKey HAND = ContextKey.direct("hand"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java new file mode 100644 index 000000000..8557ea408 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.world.World; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class ItemParameterProvider implements ChainParameterProvider> { + private static final Map, Function, Object>> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Item::id); + CONTEXT_FUNCTIONS.put(DirectContextParameters.CUSTOM_MODEL_DATA, i -> i.customModelData().orElse(null)); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, Item world) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(world)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java index cacf39e98..ddc921a0a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java @@ -14,6 +14,7 @@ public class WorldParameterProvider implements ChainParameterProvider { static { CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, World::name); CONTEXT_FUNCTIONS.put(DirectContextParameters.TIME, World::time); + CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, World::uuid); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java deleted file mode 100644 index 21f735b3c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.momirealms.craftengine.core.plugin.event; - -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; -import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.ResourceKey; - -import java.util.Map; - -public class BlockEventFunctions { - - static { - register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(BlockEventConditions::fromMap)); - } - - public static void register(Key key, FunctionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_FUNCTION_FACTORY.location(), key)); - holder.bindValue(factory); - } - - public static Function fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "TODO I18N"); - Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - FunctionFactory factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); - if (factory == null) { - throw new LocalizedResourceConfigException("TODO I18N", type); - } - return factory.create(map); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java similarity index 81% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java index 146afc563..c55f3cf4f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java @@ -14,17 +14,17 @@ import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Map; -public class BlockEventConditions { +public class EventConditions { static { register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>()); register(CommonConditions.MATCH_BLOCK_PROPERTY, new MatchBlockPropertyCondition.FactoryImpl<>()); register(CommonConditions.TABLE_BONUS, new TableBonusCondition.FactoryImpl<>()); register(CommonConditions.SURVIVES_EXPLOSION, new SurvivesExplosionCondition.FactoryImpl<>()); - register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); - register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(EventConditions::fromMap)); + register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(EventConditions::fromMap)); register(CommonConditions.ENCHANTMENT, new EnchantmentCondition.FactoryImpl<>()); - register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(EventConditions::fromMap)); register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); @@ -32,24 +32,24 @@ public class BlockEventConditions { } public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_CONDITION_FACTORY.location(), key)); + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_CONDITION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.EVENT_CONDITION_FACTORY.location(), key)); holder.bindValue(factory); } public static Condition fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.event.condition.missing_type"); + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.event.condition.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); if (key.value().charAt(0) == '!') { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + ConditionFactory factory = BuiltInRegistries.EVENT_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + throw new LocalizedResourceConfigException("warning.config.event.condition.invalid_type", type); } return new InvertedCondition<>(factory.create(map)); } else { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); + ConditionFactory factory = BuiltInRegistries.EVENT_CONDITION_FACTORY.getValue(key); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + throw new LocalizedResourceConfigException("warning.config.event.condition.invalid_type", type); } return factory.create(map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java new file mode 100644 index 000000000..91dc5df2a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java @@ -0,0 +1,101 @@ +package net.momirealms.craftengine.core.plugin.event; + +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; +import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +public class EventFunctions { + + static { + register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(EventConditions::fromMap)); + } + + public static void register(Key key, FunctionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_FUNCTION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.EVENT_FUNCTION_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static Function fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.function.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + FunctionFactory factory = BuiltInRegistries.EVENT_FUNCTION_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.function.invalid_type", type); + } + return factory.create(map); + } + + public static EnumMap>> parseEvents(Object eventsObj) { + EnumMap>> events = new EnumMap<>(EventTrigger.class); + if (eventsObj instanceof Map eventsSection) { + Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); + for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { + try { + EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); + if (eventEntry.getValue() instanceof List list) { + if (list.size() == 1) { + events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); + } else if (list.size() == 2) { + events.put(eventTrigger, List.of( + EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), + EventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) + )); + } else { + List> eventsList = new ArrayList<>(); + for (Object event : list) { + eventsList.add(EventFunctions.fromMap(MiscUtils.castToMap(event, false))); + } + events.put(eventTrigger, eventsList); + } + } else if (eventEntry.getValue() instanceof Map eventSection) { + events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); + } + } + } else if (eventsObj instanceof List list) { + @SuppressWarnings("unchecked") + List> eventsList = (List>) list; + for (Map eventSection : eventsList) { + Object onObj = eventSection.get("on"); + if (onObj == null) { + throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); + } + try { + EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); + if (eventSection.containsKey("type")) { + Function function = EventFunctions.fromMap(eventSection); + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); + } else if (eventSection.containsKey("functions")) { + @SuppressWarnings("unchecked") + List> functionList = (List>) eventSection.get("functions"); + for (Map function : functionList) { + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(EventFunctions.fromMap(function)); + } + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); + } + } + } + return events; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java index 7e9ef2820..72dd20745 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -9,7 +9,8 @@ public enum EventTrigger { LEFT_CLICK("attack", "left_click"), RIGHT_CLICK("right_click", "use_on", "use", "use_item_on"), CONSUME("eat", "consume", "drink"), - BREAK("break", "dig"),; + BREAK("break", "dig"), + PLACE("place", "build"),; public static final Map BY_NAME = new HashMap<>(); private final String[] names; diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 70a3666b1..708f00d80 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -52,8 +52,8 @@ public class BuiltInRegistries { public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); - public static final Registry> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); - public static final Registry> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); + public static final Registry> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY); + public static final Registry> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index e8b6abaeb..5d0ab47b6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -53,6 +53,6 @@ public class Registries { public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); - public static final ResourceKey>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); + public static final ResourceKey>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); + public static final ResourceKey>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); } diff --git a/gradle.properties b/gradle.properties index 31dd432b9..8a3975c14 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.53.6 +project_version=0.0.53.7 config_version=32 lang_version=12 project_group=net.momirealms From f7016bacdf9a3ac48a9db1b4447054a37b049728 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 14 May 2025 19:33:34 +0800 Subject: [PATCH 61/73] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineBlocks.java | 1 - .../bukkit/api/CraftEngineFurniture.java | 2 - .../bukkit/block/BlockEventListener.java | 103 ++++++++---------- .../block/FallingBlockRemoveListener.java | 1 - .../item/behavior/BlockItemBehavior.java | 24 +++- .../item/behavior/FurnitureItemBehavior.java | 18 +++ .../item/listener/ItemEventListener.java | 58 +++++++--- .../bukkit/loot/BukkitVanillaLootManager.java | 1 - .../plugin/network/PacketConsumers.java | 8 +- .../craftengine/bukkit/world/BukkitWorld.java | 11 +- .../craftengine/core/item/CustomItem.java | 4 +- .../function/ApplyBonusCountFunction.java | 4 +- .../AbstractChainParameterContext.java | 2 +- .../context/condition/ClickTypeCondition.java | 44 -------- .../condition/EnchantmentCondition.java | 4 +- .../context/condition/MatchItemCondition.java | 4 +- .../condition/TableBonusCondition.java | 4 +- .../parameter/ChainContextParameters.java | 10 -- .../parameter/DirectContextParameters.java | 11 +- .../parameter/ItemParameterProvider.java | 1 - .../core/plugin/event/EventConditions.java | 1 - .../core/plugin/event/EventTrigger.java | 4 +- .../craftengine/core/util/Cancellable.java | 18 +++ 23 files changed, 176 insertions(+), 162 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 73ad40632..aac68bb9e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -14,7 +14,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; import net.momirealms.craftengine.core.world.WorldPosition; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index cb32e11ae..aa9616867 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; @@ -15,7 +14,6 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Location; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index f8fa97ab0..21e0ebc39 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -18,6 +18,7 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; @@ -25,7 +26,6 @@ import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -131,7 +131,7 @@ public class BlockEventListener implements Listener { return; } - // trigger event + // trigger api event CustomBlockBreakEvent customBreakEvent = new CustomBlockBreakEvent(serverPlayer, location, block, state); boolean isCancelled = EventUtils.fireAndCheckCancel(customBreakEvent); if (isCancelled) { @@ -139,12 +139,24 @@ public class BlockEventListener implements Listener { return; } - // execute functions + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + + // execute functions + Cancellable cancellable = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withParameter(DirectContextParameters.BLOCK_STATE, state)); + .withParameter(DirectContextParameters.BLOCK_STATE, state) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, position) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + ); state.owner().value().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + event.setCancelled(true); + return; + } // handle waterlogged blocks @SuppressWarnings("unchecked") @@ -157,13 +169,11 @@ public class BlockEventListener implements Listener { } // play sound - WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); world.playBlockSound(position, state.sounds().breakSound()); if (player.getGameMode() == GameMode.CREATIVE || !customBreakEvent.dropItems()) { return; } - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); // do not drop if it's not the correct tool if (!BlockStateUtils.isCorrectTool(state, itemInHand)) { return; @@ -172,8 +182,9 @@ public class BlockEventListener implements Listener { // drop items ContextHolder.Builder builder = ContextHolder.builder() .withParameter(DirectContextParameters.POSITION, position) - .withParameter(DirectContextParameters.PLAYER, serverPlayer); - //mark item .withOptionalParameter(CommonParameters.MAIN_HAND_ITEM, itemInHand); + .withParameter(DirectContextParameters.PLAYER, serverPlayer) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand); for (Item item : state.getDrops(builder, world, serverPlayer)) { world.dropItemNaturally(position, item); } @@ -191,8 +202,10 @@ public class BlockEventListener implements Listener { net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.POSITION, position) - .withParameter(DirectContextParameters.PLAYER, serverPlayer); + .withParameter(DirectContextParameters.PLAYER, serverPlayer) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { for (Item item : lootTable.getRandomItems(contextHolder, world, serverPlayer)) { @@ -230,9 +243,9 @@ public class BlockEventListener implements Listener { Location location = block.getLocation(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(block.getWorld()); WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - for (Item item : immutableBlockState.getDrops(builder, world, null)) { + for (Item item : immutableBlockState.getDrops(ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)), world, null)) { world.dropItemNaturally(position, item); } } @@ -243,15 +256,14 @@ public class BlockEventListener implements Listener { event.getDrops().clear(); event.setExpToDrop(0); } - Location location = block.getLocation(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - ContextHolder contextHolder = builder.build(); + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)); for (LootTable lootTable : it.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world, null)) { + for (Item item : lootTable.getRandomItems(builder.build(), world, null)) { world.dropItemNaturally(position, item); } } @@ -259,26 +271,37 @@ public class BlockEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true) + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) public void onStep(GenericGameEvent event) { if (event.getEvent() != GameEvent.STEP) return; Entity entity = event.getEntity(); if (!(entity instanceof Player player)) return; BlockPos pos = EntityUtils.getOnPos(player); - Location playerLocation = player.getLocation(); - BlockData blockData = player.getWorld().getBlockData(pos.x(), pos.y(), pos.z()); - Object blockState = BlockStateUtils.blockDataToBlockState(blockData); + Block block = player.getWorld().getBlockAt(pos.x(), pos.y(), pos.z()); + Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); int stateId = BlockStateUtils.blockStateToId(blockState); if (!BlockStateUtils.isVanillaBlock(stateId)) { + Location location = player.getLocation(); ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId); - player.playSound(playerLocation, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume(), state.sounds().stepSound().pitch()); + Cancellable cancellable = Cancellable.dummy(); + state.owner().value().execute(PlayerOptionalContext.of(this.plugin.adapt(player), ContextHolder.builder() + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(event.getWorld()), LocationUtils.toVec3d(location))) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withParameter(DirectContextParameters.BLOCK_STATE, state) + ), EventTrigger.STEP); + if (cancellable.isCancelled()) { + event.setCancelled(true); + return; + } + player.playSound(location, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume(), state.sounds().stepSound().pitch()); } else if (Config.enableSoundSystem()) { Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); if (manager.isBlockSoundRemoved(ownerBlock)) { try { Object soundType = Reflections.field$BlockBehaviour$soundType.get(ownerBlock); Object stepSound = Reflections.field$SoundType$stepSound.get(soundType); - player.playSound(playerLocation, FastNMS.INSTANCE.field$SoundEvent$location(stepSound).toString(), SoundCategory.BLOCKS, 0.15f, 1f); + player.playSound(player.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(stepSound).toString(), SoundCategory.BLOCKS, 0.15f, 1f); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to get sound type", e); } @@ -286,39 +309,6 @@ public class BlockEventListener implements Listener { } } -// Use BlockBreakBlock event -// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) -// public void onPistonRetract(BlockPistonRetractEvent event) { -// handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); -// } -// -// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) -// public void onPistonExtend(BlockPistonExtendEvent event) { -// handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); -// } -// -// private void handlePistonEvent(BlockFace face, List blocksList, Block piston) { -// int blocks = blocksList.size(); -// net.momirealms.craftengine.core.world.World world = new BukkitWorld(piston.getWorld()); -// for (int i = blocks - 1; i >= 0; --i) { -// Location oldLocation = blocksList.get(i).getLocation(); -// BlockPos oldPos = new BlockPos(oldLocation.getBlockX(), oldLocation.getBlockY(), oldLocation.getBlockZ()); -// Block block = blocksList.get(i); -// ImmutableBlockState blockState = manager.getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); -// if (blockState != null && blockState.pushReaction() == PushReaction.DESTROY) { -// // break actions -// ContextHolder.Builder builder = ContextHolder.builder(); -// Vec3d vec3d = Vec3d.atCenterOf(oldPos); -// builder.withParameter(LootParameters.LOCATION, vec3d); -// builder.withParameter(LootParameters.WORLD, world); -// for (Item item : blockState.getDrops(builder, world)) { -// world.dropItemNaturally(vec3d, item); -// } -// world.playBlockSound(vec3d, blockState.sounds().breakSound()); -// } -// } -// } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onEntityExplode(EntityExplodeEvent event) { if (VersionHelper.isOrAbove1_21()) { @@ -344,7 +334,8 @@ public class BlockEventListener implements Listener { if (state != null && !state.isEmpty()) { WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(blockPos)); ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)); if (yield < 1f) { builder.withParameter(DirectContextParameters.EXPLOSION_RADIUS, 1.0f / yield); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java index 60510e94a..546ef9ad4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/FallingBlockRemoveListener.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.entity.FallingBlock; import org.bukkit.event.EventHandler; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 39d62f1e4..00fbf33cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -22,12 +23,17 @@ 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.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.GameEvent; import org.bukkit.Location; @@ -137,6 +143,20 @@ public class BlockItemBehavior extends ItemBehavior { return InteractionResult.FAIL; } + WorldPosition position = new WorldPosition(context.getLevel(), pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5); + Cancellable dummy = Cancellable.dummy(); + PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(bukkitBlock)) + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.HAND, context.getHand()) + .withParameter(DirectContextParameters.ITEM_IN_HAND, context.getItem()) + ); + block.execute(functionContext, EventTrigger.PLACE); + if (dummy.isCancelled()) { + return InteractionResult.SUCCESS_AND_CANCEL; + } + if (!player.isCreativeMode()) { Item item = context.getItem(); item.count(item.count() - 1); @@ -144,7 +164,7 @@ public class BlockItemBehavior extends ItemBehavior { } player.swingHand(context.getHand()); - context.getLevel().playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), blockStateToPlace.sounds().placeSound()); + context.getLevel().playBlockSound(position, blockStateToPlace.sounds().placeSound()); world.sendGameEvent(bukkitPlayer, GameEvent.BLOCK_PLACE, new Vector(pos.x(), pos.y(), pos.z())); return InteractionResult.SUCCESS; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index d31586809..20773f4f1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; @@ -20,6 +21,10 @@ 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.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; @@ -143,6 +148,19 @@ public class FurnitureItemBehavior extends ItemBehavior { return InteractionResult.FAIL; } + Cancellable dummy = Cancellable.dummy(); + PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, loadedFurniture) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation)) + .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.HAND, context.getHand()) + .withParameter(DirectContextParameters.ITEM_IN_HAND, item) + ); + customFurniture.execute(functionContext, EventTrigger.PLACE); + if (dummy.isCancelled()) { + return InteractionResult.SUCCESS_AND_CANCEL; + } + if (!player.isCreativeMode()) { item.count(item.count() - 1); item.load(); 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 95f404fef..183db3a06 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 @@ -14,12 +14,11 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; -import net.momirealms.craftengine.core.plugin.context.CommonParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.event.EventTrigger; -import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; @@ -75,6 +74,7 @@ public class ItemEventListener implements Listener { Object blockState = BlockStateUtils.blockDataToBlockState(blockData); ImmutableBlockState immutableBlockState = null; int stateId = BlockStateUtils.blockStateToId(blockState); + Item itemInHand = serverPlayer.getItemInHand(hand); // 处理自定义方块 if (!BlockStateUtils.isVanillaBlock(stateId)) { @@ -96,19 +96,25 @@ public class ItemEventListener implements Listener { return; } + Cancellable dummy = Cancellable.dummy(); // run custom functions CustomBlock customBlock = immutableBlockState.owner().value(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); - customBlock.execute(context, EventTrigger.CLICK); + .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + ); if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); else customBlock.execute(context, EventTrigger.LEFT_CLICK); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } - Item itemInHand = serverPlayer.getItemInHand(hand); Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); boolean hasItem = itemInHand != null; boolean hasCustomItem = optionalCustomItem.isPresent(); @@ -157,16 +163,23 @@ public class ItemEventListener implements Listener { } } - // execute item functions + // execute item right click functions if (hasCustomItem) { + Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); + .withParameter(DirectContextParameters.EVENT, dummy) + ); CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.CLICK); customItem.execute(context, EventTrigger.RIGHT_CLICK); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } // 检查其他的物品行为,物品行为理论只在交互时处理 @@ -196,14 +209,20 @@ public class ItemEventListener implements Listener { } if (hasCustomItem && action == Action.LEFT_CLICK_BLOCK) { + Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + ); CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.CLICK); customItem.execute(context, EventTrigger.LEFT_CLICK); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } } @@ -222,17 +241,18 @@ public class ItemEventListener implements Listener { // should never be null if (itemInHand == null) return; - if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { - return; - } + // todo 真的需要这个吗 +// if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { +// return; +// } Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isPresent()) { PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + ); CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.CLICK); if (action.isRightClick()) customItem.execute(context, EventTrigger.RIGHT_CLICK); else customItem.execute(context, EventTrigger.LEFT_CLICK); } @@ -254,7 +274,7 @@ public class ItemEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true) + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) public void onConsumeItem(PlayerItemConsumeEvent event) { ItemStack consumedItem = event.getItem(); if (ItemUtils.isEmpty(consumedItem)) return; @@ -263,12 +283,18 @@ public class ItemEventListener implements Listener { if (optionalCustomItem.isEmpty()) { return; } + Cancellable dummy = Cancellable.dummy(); CustomItem customItem = optionalCustomItem.get(); PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() .withParameter(DirectContextParameters.CONSUMED_ITEM, wrapped) + .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) ); customItem.execute(context, EventTrigger.CONSUME); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index c64de703d..2a1d1630b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -17,7 +17,6 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; 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 d0326c8cc..abd76f731 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 @@ -1695,9 +1695,8 @@ public class PacketConsumers { PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.FURNITURE, furniture) .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) - .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + ); furniture.config().execute(context, EventTrigger.LEFT_CLICK); - furniture.config().execute(context, EventTrigger.CLICK); furniture.config().execute(context, EventTrigger.BREAK); CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); @@ -1726,9 +1725,8 @@ public class PacketConsumers { PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.FURNITURE, furniture) .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) - .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); - furniture.config().execute(context, EventTrigger.RIGHT_CLICK); - furniture.config().execute(context, EventTrigger.CLICK); + ); + furniture.config().execute(context, EventTrigger.RIGHT_CLICK);; if (player.isSneaking()) { // try placing another furniture above it diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index c8326c920..1554d3d79 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -6,7 +6,10 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.BlockInWorld; +import net.momirealms.craftengine.core.world.Position; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldHeight; import org.bukkit.Location; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; @@ -32,11 +35,7 @@ public class BukkitWorld implements World { @Override public Object serverWorld() { - try { - return FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformWorld()); - } catch (Exception e) { - throw new RuntimeException("Failed to get server world", e); - } + return FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformWorld()); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index b30c543a9..8f92db2d7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -9,7 +9,9 @@ import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; public interface CustomItem extends BuildableItem { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index 52a6f8d5e..ddca1c41d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -31,7 +31,7 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< @Override protected Item applyInternal(Item item, LootContext context) { - Optional> itemInHand = context.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); + Optional> itemInHand = context.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); int level = itemInHand.map(value -> value.getEnchantment(this.enchantment).map(Enchantment::level).orElse(0)).orElse(0); int newCount = this.formula.apply(item.count(), level); item.count(newCount); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index fc9b57f60..14bde9ccb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -19,7 +19,7 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.CONSUMED_ITEM, itemProvider); - CHAIN_PARAMETERS.put(DirectContextParameters.TOOL, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.ITEM_IN_HAND, itemProvider); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java deleted file mode 100644 index 15da85637..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ClickTypeCondition.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context.condition; - -import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.ClickType; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; - -import java.util.Locale; -import java.util.Map; -import java.util.Optional; - -public class ClickTypeCondition implements Condition { - private final ClickType clickType; - - public ClickTypeCondition(ClickType clickType) { - this.clickType = clickType; - } - - @Override - public Key type() { - return CommonConditions.CLICK_TYPE; - } - - @Override - public boolean test(CTX ctx) { - Optional clickTypeOptional = ctx.getOptionalParameter(DirectContextParameters.CLICK_TYPE); - if (clickTypeOptional.isPresent()) { - ClickType clickType = clickTypeOptional.get(); - return clickType.equals(this.clickType); - } - return false; - } - - public static class FactoryImpl implements ConditionFactory { - - @Override - public Condition create(Map arguments) { - ClickType clickType = ClickType.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("click-type"), "warning.config.condition.click_type.missing_click_type").toUpperCase(Locale.ENGLISH)); - return new ClickTypeCondition<>(clickType); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java index d9b539a06..0be266bd5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -29,7 +29,7 @@ public class EnchantmentCondition implements Condition @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); if (item.isEmpty()) return false; Optional enchantment = item.get().getEnchantment(id); int level = enchantment.map(Enchantment::level).orElse(0); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java index 84036263f..c61398043 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -26,7 +26,7 @@ public class MatchItemCondition implements Condition { @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); if (item.isEmpty()) return false; Key key = item.get().id(); String itemId = key.toString(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java index e73652cca..780643a19 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.plugin.context.parameter.ChainContextParameters; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -31,7 +31,7 @@ public class TableBonusCondition implements Condition @Override public boolean test(CTX ctx) { - Optional> item = ctx.getOptionalParameter(ChainContextParameters.PLAYER_MAIN_HAND_ITEM); + Optional> item = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); int level = item.map(value -> value.getEnchantment(this.enchantmentType).map(Enchantment::level).orElse(0)).orElse(0); float f = this.values.get(Math.min(level, this.values.size() - 1)); return RandomUtils.generateRandomFloat(0, 1) < f; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java deleted file mode 100644 index 03f350952..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ChainContextParameters.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.momirealms.craftengine.core.plugin.context.parameter; - -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.context.ContextKey; - -public final class ChainContextParameters { - private ChainContextParameters() {} - - public static final ContextKey> PLAYER_MAIN_HAND_ITEM = ContextKey.chain("player.main_hand_item"); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 0d930d0f9..5fcee23b8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -8,9 +8,12 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.BlockInWorld; +import net.momirealms.craftengine.core.world.Position; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; import java.util.UUID; @@ -22,11 +25,10 @@ public final class DirectContextParameters { public static final ContextKey WORLD = ContextKey.direct("world"); public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); public static final ContextKey> CONSUMED_ITEM = ContextKey.direct("consumed_item"); - public static final ContextKey> TOOL = ContextKey.direct("tool"); + public static final ContextKey> ITEM_IN_HAND = ContextKey.direct("item_in_hand"); public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); public static final ContextKey PLAYER = ContextKey.direct("player"); - public static final ContextKey CLICK_TYPE = ContextKey.direct("click_type"); public static final ContextKey BLOCK_STATE = ContextKey.direct("custom_block_state"); public static final ContextKey COORDINATE = ContextKey.direct("coordinate"); public static final ContextKey POSITION = ContextKey.direct("position"); @@ -48,4 +50,5 @@ public final class DirectContextParameters { public static final ContextKey FURNITURE = ContextKey.direct("furniture"); public static final ContextKey ANCHOR_TYPE = ContextKey.direct("anchor_type"); public static final ContextKey HAND = ContextKey.direct("hand"); + public static final ContextKey EVENT = ContextKey.direct("event"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java index 8557ea408..b933a6eba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.world.World; import java.util.HashMap; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java index c55f3cf4f..d2d6d7c4c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java @@ -28,7 +28,6 @@ public class EventConditions { register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); - register(CommonConditions.CLICK_TYPE, new ClickTypeCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java index 72dd20745..8c7060079 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -5,12 +5,12 @@ import java.util.Map; import java.util.Optional; public enum EventTrigger { - CLICK("click", "interact"), LEFT_CLICK("attack", "left_click"), RIGHT_CLICK("right_click", "use_on", "use", "use_item_on"), CONSUME("eat", "consume", "drink"), BREAK("break", "dig"), - PLACE("place", "build"),; + PLACE("place", "build"), + STEP("step"),; public static final Map BY_NAME = new HashMap<>(); private final String[] names; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java b/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java index d9decdb44..314ad9ce3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java @@ -5,4 +5,22 @@ public interface Cancellable { boolean isCancelled(); void setCancelled(boolean cancel); + + static Cancellable dummy() { + return new Dummy(); + } + + class Dummy implements Cancellable { + private boolean cancelled; + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + } } From c047e5a83c51a4320730e716ca039e23bacd4cc4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 14 May 2025 21:44:56 +0800 Subject: [PATCH 62/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E6=9D=A1=E4=BB=B6=E5=92=8C=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 还需要对vanilla-loots系统进行重构 --- .../src/main/resources/translations/en.yml | 12 ++- .../src/main/resources/translations/zh_cn.yml | 3 +- .../bukkit/block/BlockEventListener.java | 50 +++++++---- .../bukkit/entity/BukkitEntity.java | 11 +++ .../plugin/user/BukkitServerPlayer.java | 37 ++++++--- .../craftengine/core/entity/Entity.java | 6 ++ .../core/entity/player/GameMode.java | 18 ++++ .../core/entity/player/Player.java | 28 +++++-- .../craftengine/core/loot/LootConditions.java | 3 + .../AbstractChainParameterContext.java | 2 + .../context/condition/CommonConditions.java | 3 +- .../context/condition/EqualsCondition.java | 40 +++++++++ .../condition/ExpressionCondition.java | 48 +++++++++++ .../condition/PermissionCondition.java | 39 +++++++++ .../context/function/ActionBarFunction.java | 61 ++++++++++++++ .../context/function/CancelEventFunction.java | 41 ++++++++++ .../context/function/CommandFunction.java | 4 +- .../context/function/MessageFunction.java | 4 +- .../context/function/TitleFunction.java | 82 +++++++++++++++++++ .../parameter/DirectContextParameters.java | 7 ++ .../parameter/EntityParameterProvider.java | 33 ++++++++ .../parameter/FurnitureParameterProvider.java | 25 ++++++ .../parameter/ItemParameterProvider.java | 1 + .../parameter/PlayerParameterProvider.java | 3 + .../context/selector/AllPlayerSelector.java | 12 +++ .../selector/PlayerSelectorFactory.java | 12 +++ .../context/selector/PlayerSelectors.java | 67 ++++++++------- .../context/selector/SelfPlayerSelector.java | 10 +++ .../core/plugin/event/EventConditions.java | 3 + .../core/plugin/event/EventFunctions.java | 9 +- .../core/registry/BuiltInRegistries.java | 2 + .../craftengine/core/registry/Registries.java | 6 +- 32 files changed, 608 insertions(+), 74 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/player/GameMode.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ExpressionCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/PermissionCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CancelEventFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectorFactory.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index e8dca66a7..ac1084288 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -90,7 +90,10 @@ warning.config.condition.match_block_property.missing_properties: "Issue warning.config.condition.match_item.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'match_item' condition." warning.config.condition.table_bonus.missing_enchantment: "Issue found in file - The config '' is missing the required 'enchantment' argument for 'table_bonus' condition." warning.config.condition.table_bonus.missing_chances: "Issue found in file - The config '' is missing the required 'chances' argument for 'table_bonus' condition." -warning.config.condition.click_type.missing_click_type: "Issue found in file - The config '' is missing the required 'click-type' argument for 'click_type' condition." +warning.config.condition.permission.missing_permission: "Issue found in file - The config '' is missing the required 'permission' argument for 'permission' condition." +warning.config.condition.equals.missing_value1: "Issue found in file - The config '' is missing the required 'value1' argument for 'equals' condition." +warning.config.condition.equals.missing_value2: "Issue found in file - The config '' is missing the required 'value2' argument for 'equals' condition." +warning.config.condition.expression.missing_expression: "Issue found in file - The config '' is missing the required 'expression' argument for 'expression' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -302,4 +305,9 @@ warning.config.event.condition.missing_type: "Issue found in file Issue found in file - The config '' is using an invalid 'type' argument '' for event condition." warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." +warning.config.function.actionbar.missing_actionbar: "Issue found in file - The config '' is missing the required 'actionbar' argument for 'actionbar' function." +warning.config.function.message.missing_message: "Issue found in file - The config '' is missing the required 'message' argument for 'message' function." +warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." +warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." +warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index a8c511c27..f0f71519f 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -90,7 +90,8 @@ warning.config.condition.match_block_property.missing_properties: "在 warning.config.condition.match_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'match_item' 条件所需的 'id' 参数" warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" -warning.config.condition.click_type.missing_click_type: "Issue found in file - The config '' is missing the required 'click-type' argument for 'click_type' condition." + + warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 21e0ebc39..070c400b4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.config.Config; @@ -42,6 +43,7 @@ import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Optional; public class BlockEventListener implements Listener { private final BukkitCraftEngine plugin; @@ -121,11 +123,35 @@ public class BlockEventListener implements Listener { Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); int stateId = BlockStateUtils.blockStateToId(blockState); Player player = event.getPlayer(); + Location location = block.getLocation(); + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); + WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + + if (itemInHand != null) { + Optional> optionalCustomItem = itemInHand.getCustomItem(); + if (optionalCustomItem.isPresent()) { + Cancellable dummy = Cancellable.dummy(); + optionalCustomItem.get().execute( + PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.PLAYER, serverPlayer) + .withParameter(DirectContextParameters.EVENT, dummy) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + ), EventTrigger.BREAK + ); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } + } + } + if (!BlockStateUtils.isVanillaBlock(stateId)) { ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId); if (!state.isEmpty()) { - Location location = block.getLocation(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); // double check adventure mode to prevent dupe if (!FastNMS.INSTANCE.mayBuild(serverPlayer.serverPlayer()) && !serverPlayer.canBreak(LocationUtils.toBlockPos(location), null)) { return; @@ -139,10 +165,6 @@ public class BlockEventListener implements Listener { return; } - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); - WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - // execute functions Cancellable cancellable = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() @@ -180,12 +202,12 @@ public class BlockEventListener implements Listener { } // drop items - ContextHolder.Builder builder = ContextHolder.builder() + ContextHolder.Builder lootContext = ContextHolder.builder() .withParameter(DirectContextParameters.POSITION, position) .withParameter(DirectContextParameters.PLAYER, serverPlayer) .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand); - for (Item item : state.getDrops(builder, world, serverPlayer)) { + for (Item item : state.getDrops(lootContext, world, serverPlayer)) { world.dropItemNaturally(position, item); } } @@ -197,23 +219,19 @@ public class BlockEventListener implements Listener { event.setDropItems(false); event.setExpToDrop(0); } - Location location = block.getLocation(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); - WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - ContextHolder.Builder builder = ContextHolder.builder() + ContextHolder lootContext = ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.POSITION, position) .withParameter(DirectContextParameters.PLAYER, serverPlayer) - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); - ContextHolder contextHolder = builder.build(); + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand).build(); for (LootTable lootTable : it.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world, serverPlayer)) { + for (Item item : lootTable.getRandomItems(lootContext, world, serverPlayer)) { world.dropItemNaturally(position, item); } } }); } + // sound system if (Config.enableSoundSystem()) { Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index 536217d46..ffe08c8fd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import java.lang.ref.WeakReference; +import java.util.UUID; public class BukkitEntity extends AbstractEntity { private final WeakReference entity; @@ -69,4 +70,14 @@ public class BukkitEntity extends AbstractEntity { public Key type() { return KeyUtils.namespacedKey2Key(literalObject().getType().getKey()); } + + @Override + public String name() { + return literalObject().getName(); + } + + @Override + public UUID uuid() { + return literalObject().getUniqueId(); + } } 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 1d4086b39..5e045570f 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 @@ -13,6 +13,7 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.BlockSettings; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.PackedBlockState; +import net.momirealms.craftengine.core.entity.player.GameMode; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; @@ -27,7 +28,10 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; -import org.bukkit.*; +import org.bukkit.FluidCollisionMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.SoundCategory; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; @@ -145,18 +149,18 @@ public class BukkitServerPlayer extends Player { } @Override - public boolean isCreativeMode() { - return platformPlayer().getGameMode() == GameMode.CREATIVE; + public GameMode gameMode() { + return switch (platformPlayer().getGameMode()) { + case CREATIVE -> GameMode.CREATIVE; + case SPECTATOR -> GameMode.SPECTATOR; + case ADVENTURE -> GameMode.ADVENTURE; + case SURVIVAL -> GameMode.SURVIVAL; + }; } @Override - public boolean isSpectatorMode() { - return platformPlayer().getGameMode() == GameMode.SPECTATOR; - } - - @Override - public boolean isAdventureMode() { - return platformPlayer().getGameMode() == GameMode.ADVENTURE; + public void setGameMode(GameMode gameMode) { + platformPlayer().setGameMode(Objects.requireNonNull(org.bukkit.GameMode.getByValue(gameMode.id()))); } @Override @@ -175,6 +179,14 @@ public class BukkitServerPlayer extends Player { sendPacket(packet, false); } + @Override + public void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut) { + Object titlePacket = FastNMS.INSTANCE.constructor$ClientboundSetTitleTextPacket(ComponentUtils.adventureToMinecraft(title)); + Object subtitlePacket = FastNMS.INSTANCE.constructor$ClientboundSetSubtitleTextPacket(ComponentUtils.adventureToMinecraft(subtitle)); + Object timePacket = FastNMS.INSTANCE.constructor$ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + sendPackets(List.of(titlePacket, subtitlePacket, timePacket), false); + } + @Override public void sendMessage(Component text, boolean overlay) { Object packet = FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(text), overlay); @@ -816,4 +828,9 @@ public class BukkitServerPlayer extends Player { return LegacyAttributeUtils.getLuck(platformPlayer()); } } + + @Override + public boolean isFlying() { + return platformPlayer().isFlying(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index 8c9958a36..15720fa5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -5,6 +5,8 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; +import java.util.UUID; + public interface Entity { Key type(); @@ -29,4 +31,8 @@ public interface Entity { Direction getDirection(); Object literalObject(); + + String name(); + + UUID uuid(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/GameMode.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/GameMode.java new file mode 100644 index 000000000..716ce0ba3 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/GameMode.java @@ -0,0 +1,18 @@ +package net.momirealms.craftengine.core.entity.player; + +public enum GameMode { + SURVIVAL(0), + CREATIVE(1), + ADVENTURE(2), + SPECTATOR(3); + + private final int id; + + GameMode(int id) { + this.id = id; + } + + public int id() { + return id; + } +} 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 81a9b77c3..bb50aec7d 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 @@ -46,11 +46,9 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract boolean isSneaking(); - public abstract boolean isCreativeMode(); + public abstract GameMode gameMode(); - public abstract boolean isSpectatorMode(); - - public abstract boolean isAdventureMode(); + public abstract void setGameMode(GameMode gameMode); public abstract boolean canBreak(BlockPos pos, Object state); @@ -60,6 +58,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void sendMessage(Component text, boolean overlay); + public abstract void sendTitle(Component title, Component subtitle, int fadeIn, int stay, int fadeOut); + public abstract boolean updateLastSuccessfulInteractionTick(int tick); public abstract int lastSuccessfulInteractionTick(); @@ -75,7 +75,7 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract String name(); public void playSound(Key sound) { - playSound(sound, 1, 1); + playSound(sound, 1f, 1f); } public abstract void playSound(Key sound, float volume, float pitch); @@ -92,8 +92,26 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract double luck(); + public abstract boolean isFlying(); + @Override public Key type() { return TYPE; } + + public boolean isCreativeMode() { + return gameMode() == GameMode.CREATIVE; + } + + public boolean isSpectatorMode() { + return gameMode() == GameMode.SPECTATOR; + } + + public boolean isSurvivalMode() { + return gameMode() == GameMode.SURVIVAL; + } + + public boolean isAdventureMode() { + return gameMode() == GameMode.ADVENTURE; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 0dc4c9a32..43ca9b0aa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -30,6 +30,9 @@ public class LootConditions { register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); + register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); + register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); + register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index 14bde9ccb..9eed4f51b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -14,6 +14,8 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.WORLD, new WorldParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.BLOCK, new BlockParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.POSITION, new PositionParameterProvider()); + CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE, new FurnitureParameterProvider()); + CHAIN_PARAMETERS.put(DirectContextParameters.ENTITY, new EntityParameterProvider()); ItemParameterProvider itemProvider = new ItemParameterProvider(); CHAIN_PARAMETERS.put(DirectContextParameters.MAIN_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 7c6f06c33..600d204c8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -10,7 +10,6 @@ public final class CommonConditions { public static final Key ANY_OF = Key.of("craftengine:any_of"); public static final Key INVERTED = Key.of("craftengine:inverted"); public static final Key MATCH_ITEM = Key.of("craftengine:match_item"); - public static final Key CLICK_TYPE = Key.of("craftengine:click_type"); public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); @@ -19,4 +18,6 @@ public final class CommonConditions { public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key DISTANCE = Key.from("craftengine:distance"); public static final Key PERMISSION = Key.from("craftengine:permission"); + public static final Key EQUALS = Key.from("craftengine:equals"); + public static final Key EXPRESSION = Key.from("craftengine:expression"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java new file mode 100644 index 000000000..bc48c0a1a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class EqualsCondition implements Condition { + private final TextProvider value1; + private final TextProvider value2; + + public EqualsCondition(TextProvider value1, TextProvider value2) { + this.value1 = value1; + this.value2 = value2; + } + + @Override + public Key type() { + return CommonConditions.EQUALS; + } + + @Override + public boolean test(CTX ctx) { + return this.value1.get(ctx).equals(this.value2.get(ctx)); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String value1 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.equals.missing_value1"); + String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.equals.missing_value2"); + return new EqualsCondition<>(TextProviders.fromString(value1), TextProviders.fromString(value2)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ExpressionCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ExpressionCondition.java new file mode 100644 index 000000000..7ae158e1f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/ExpressionCondition.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.parser.ParseException; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class ExpressionCondition implements Condition { + private final TextProvider expression; + + public ExpressionCondition(TextProvider expression) { + this.expression = expression; + } + + @Override + public Key type() { + return CommonConditions.EXPRESSION; + } + + @Override + public boolean test(CTX ctx) { + String exp = expression.get(ctx); + Expression expr = new Expression(exp); + try { + return expr.evaluate().getBooleanValue(); + } catch (ParseException | EvaluationException e) { + CraftEngine.instance().logger().warn("Invalid expression " + exp, e); + return false; + } + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String value = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("expression"), "warning.config.condition.expression.missing_expression"); + return new ExpressionCondition<>(TextProviders.fromString(value)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/PermissionCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/PermissionCondition.java new file mode 100644 index 000000000..2a7a7f829 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/PermissionCondition.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.Optional; + +public class PermissionCondition implements Condition { + private final String permission; + + public PermissionCondition(String permission) { + this.permission = permission; + } + + @Override + public Key type() { + return CommonConditions.PERMISSION; + } + + @Override + public boolean test(CTX ctx) { + Optional player = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + return player.map(value -> value.hasPermission(this.permission)).orElse(false); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String permission = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("permission"), "warning.config.condition.permission.missing_permission"); + return new PermissionCondition<>(permission); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java new file mode 100644 index 000000000..1db327924 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java @@ -0,0 +1,61 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ActionBarFunction extends AbstractConditionalFunction { + private final TextProvider message; + private final PlayerSelector selector; + + public ActionBarFunction(List> predicates, @Nullable PlayerSelector selector, TextProvider messages) { + super(predicates); + this.message = messages; + this.selector = selector; + } + + @Override + public void runInternal(CTX ctx) { + Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + if (this.selector == null) { + owner.ifPresent(it -> { + it.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(ctx), ctx.tagResolvers())); + }); + } else { + for (Player viewer : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY)); + viewer.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(relationalContext), relationalContext.tagResolvers())); + } + } + } + + @Override + public Key type() { + return CommonFunctions.ACTIONBAR; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String message = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "actionbar", "message"), "warning.config.function.actionbar.missing_actionbar"); + return new ActionBarFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), TextProviders.fromString(message)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CancelEventFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CancelEventFunction.java new file mode 100644 index 000000000..4c75c7eb9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CancelEventFunction.java @@ -0,0 +1,41 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Cancellable; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class CancelEventFunction extends AbstractConditionalFunction { + + public CancelEventFunction(List> predicates) { + super(predicates); + } + + @Override + public void runInternal(CTX ctx) { + Optional cancellable = ctx.getOptionalParameter(DirectContextParameters.EVENT); + cancellable.ifPresent(value -> value.setCancelled(true)); + } + + @Override + public Key type() { + return CommonFunctions.CANCEL_EVENT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + return new CancelEventFunction<>(getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index 98c69097e..0b203a447 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -23,7 +23,7 @@ public class CommandFunction extends AbstractConditionalFun private final boolean asPlayer; private final PlayerSelector selector; - public CommandFunction(List> predicates, List command, boolean asPlayer, @Nullable PlayerSelector selector) { + public CommandFunction(List> predicates, @Nullable PlayerSelector selector, List command, boolean asPlayer) { super(predicates); this.asPlayer = asPlayer; this.command = command; @@ -72,7 +72,7 @@ public class CommandFunction extends AbstractConditionalFun Object command = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "command", "commands"), "warning.config.function.command.missing_command"); List commands = MiscUtils.getAsStringList(command).stream().map(TextProviders::fromString).toList(); boolean asPlayer = (boolean) arguments.getOrDefault("as-player", false); - return new CommandFunction<>(getPredicates(arguments), commands, asPlayer, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory())); + return new CommandFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), commands, asPlayer); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java index 541774050..1b4f2ddbd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -22,7 +22,7 @@ public class MessageFunction extends AbstractConditionalFun private final PlayerSelector selector; private final boolean overlay; - public MessageFunction(List> predicates, List messages, @Nullable PlayerSelector selector, boolean overlay) { + public MessageFunction(List> predicates, @Nullable PlayerSelector selector, List messages, boolean overlay) { super(predicates); this.messages = messages; this.selector = selector; @@ -64,7 +64,7 @@ public class MessageFunction extends AbstractConditionalFun Object message = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "messages", "message"), "warning.config.function.command.missing_message"); List messages = MiscUtils.getAsStringList(message).stream().map(TextProviders::fromString).toList(); boolean overlay = (boolean) arguments.getOrDefault("overlay", false); - return new MessageFunction<>(getPredicates(arguments), messages, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), overlay); + return new MessageFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), messages, overlay); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java new file mode 100644 index 000000000..6d55589ae --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java @@ -0,0 +1,82 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class TitleFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final TextProvider main; + private final TextProvider sub; + private final NumberProvider fadeIn; + private final NumberProvider stay; + private final NumberProvider fadeOut; + + public TitleFunction(List> predicates, @Nullable PlayerSelector selector, + TextProvider main, TextProvider sub, NumberProvider fadeIn, NumberProvider stay, NumberProvider fadeOut) { + super(predicates); + this.selector = selector; + this.main = main; + this.sub = sub; + this.fadeIn = fadeIn; + this.stay = stay; + this.fadeOut = fadeOut; + } + + @Override + public void runInternal(CTX ctx) { + Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + if (this.selector == null) { + owner.ifPresent(it -> it.sendTitle( + AdventureHelper.miniMessage().deserialize(this.main.get(ctx), ctx.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.sub.get(ctx), ctx.tagResolvers()), + this.fadeIn.getInt(ctx), this.stay.getInt(ctx), this.fadeOut.getInt(ctx) + )); + } else { + for (Player viewer : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY)); + viewer.sendTitle( + AdventureHelper.miniMessage().deserialize(this.main.get(relationalContext), relationalContext.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.sub.get(relationalContext), relationalContext.tagResolvers()), + this.fadeIn.getInt(relationalContext), this.stay.getInt(relationalContext), this.fadeOut.getInt(relationalContext) + ); + } + } + } + + @Override + public Key type() { + return CommonFunctions.TITLE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String title = arguments.getOrDefault("title", "").toString(); + String subtitle = arguments.getOrDefault("subtitle", "").toString(); + NumberProvider fadeIn = NumberProviders.fromObject(arguments.getOrDefault("fade-in", 10)); + NumberProvider stay = NumberProviders.fromObject(arguments.getOrDefault("stay", 20)); + NumberProvider fadeOut = NumberProviders.fromObject(arguments.getOrDefault("fade-out", 5)); + return new TitleFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), + TextProviders.fromString(title), TextProviders.fromString(subtitle), fadeIn, stay, fadeOut); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 5fcee23b8..151b69866 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.GameMode; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; @@ -29,6 +31,7 @@ public final class DirectContextParameters { public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); public static final ContextKey PLAYER = ContextKey.direct("player"); + public static final ContextKey ENTITY = ContextKey.direct("entity"); public static final ContextKey BLOCK_STATE = ContextKey.direct("custom_block_state"); public static final ContextKey COORDINATE = ContextKey.direct("coordinate"); public static final ContextKey POSITION = ContextKey.direct("position"); @@ -51,4 +54,8 @@ public final class DirectContextParameters { public static final ContextKey ANCHOR_TYPE = ContextKey.direct("anchor_type"); public static final ContextKey HAND = ContextKey.direct("hand"); public static final ContextKey EVENT = ContextKey.direct("event"); + public static final ContextKey IS_FLYING = ContextKey.direct("is_flying"); + public static final ContextKey IS_SNEAKING = ContextKey.direct("is_sneaking"); + public static final ContextKey IS_CUSTOM = ContextKey.direct("is_custom"); + public static final ContextKey GAMEMODE = ContextKey.direct("gamemode"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java new file mode 100644 index 000000000..b36225670 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.entity.Entity; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.MCUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class EntityParameterProvider implements ChainParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, Entity::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, Entity::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, Entity::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Entity::name); + CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Entity::uuid); + CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, Entity entity) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(entity)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java new file mode 100644 index 000000000..2f49aca37 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class FurnitureParameterProvider implements ChainParameterProvider { + private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Furniture::id); + CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Furniture::uuid); + CONTEXT_FUNCTIONS.put(DirectContextParameters.ANCHOR_TYPE, Furniture::anchorType); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, Furniture world) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(world)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java index b933a6eba..a4709072f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java @@ -14,6 +14,7 @@ public class ItemParameterProvider implements ChainParameterProvider> { static { CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Item::id); CONTEXT_FUNCTIONS.put(DirectContextParameters.CUSTOM_MODEL_DATA, i -> i.customModelData().orElse(null)); + CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_CUSTOM, Item::isCustomItem); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java index efeca907e..4075c6ff8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -26,6 +26,9 @@ public class PlayerParameterProvider implements ChainParameterProvider { CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name); CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Player::uuid); CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world); + CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_FLYING, Player::isFlying); + CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_SNEAKING, Player::isSneaking); + CONTEXT_FUNCTIONS.put(DirectContextParameters.GAMEMODE, Player::gameMode); CONTEXT_FUNCTIONS.put(DirectContextParameters.MAIN_HAND_ITEM, p -> p.getItemInHand(InteractionHand.MAIN_HAND)); CONTEXT_FUNCTIONS.put(DirectContextParameters.OFF_HAND_ITEM, p -> p.getItemInHand(InteractionHand.OFF_HAND)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java index 5b075bd98..edd33b388 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java @@ -13,6 +13,8 @@ import net.momirealms.craftengine.core.util.MCUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.function.Function; import java.util.function.Predicate; public class AllPlayerSelector implements PlayerSelector { @@ -50,4 +52,14 @@ public class AllPlayerSelector implements PlayerSelector implements PlayerSelectorFactory { + + @Override + public PlayerSelector create(Map args, Function, Condition> conditionFactory) { + + + return null; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectorFactory.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectorFactory.java new file mode 100644 index 000000000..c286c38e4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectorFactory.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.plugin.context.selector; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; + +import java.util.Map; +import java.util.function.Function; + +public interface PlayerSelectorFactory { + + PlayerSelector create(Map args, Function, Condition> conditionFactory); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java index 2887faa49..c1198e8d9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java @@ -2,12 +2,17 @@ package net.momirealms.craftengine.core.plugin.context.selector; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.function.Function; @@ -15,37 +20,41 @@ public class PlayerSelectors { public static final Key ALL = Key.of("craftengine:all"); public static final Key SELF = Key.of("craftengine:self"); + static { + register(ALL, new AllPlayerSelector.FactoryImpl<>()); + register(SELF, new SelfPlayerSelector.FactoryImpl<>()); + } + + public static void register(Key key, PlayerSelectorFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_SELECTOR_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.PLAYER_SELECTOR_FACTORY.location(), key)); + holder.bindValue(factory); + } + + @Nullable public static PlayerSelector fromObject(Object object, Function, Condition> conditionFactory) { if (object == null) return null; - if (object instanceof String string) { - if (string.equals("self") || string.equals("@self") || string.equals("@s")) { - return new SelfPlayerSelector<>(); - } else if (string.equals("all") || string.equals("@all") || string.equals("@a")) { - return new AllPlayerSelector<>(); - } - } else if (object instanceof Map map) { + if (object instanceof Map map) { Map selectorMap = MiscUtils.castToMap(map, false); - Object typeObj = selectorMap.get("type"); - Object conditionObj = ResourceConfigUtils.get(selectorMap, "conditions"); - if (!(typeObj instanceof String typeString)) { - throw new UnsupportedOperationException("Not supported yet."); - } - if (typeString.equals("all") || typeString.equals("@all") || typeString.equals("@a")) { - List> conditions = new ArrayList<>(); - if (conditionObj instanceof List list) { - @SuppressWarnings("unchecked") - List> conditionList = (List>) list; - for (Map condition : conditionList) { - conditions.add(conditionFactory.apply(condition)); - } - } else if (conditionObj instanceof Map) { - conditions.add(conditionFactory.apply(MiscUtils.castToMap(conditionObj, false))); - } else { - return new AllPlayerSelector<>(); - } - return new AllPlayerSelector<>(conditions); + return fromMap(selectorMap, conditionFactory); + } else if (object instanceof String target) { + if (target.equals("all") || target.equals("@a")) { + return new AllPlayerSelector<>(); + } else if (target.equals("self") || target.equals("@s")) { + return new SelfPlayerSelector<>(); } } - throw new UnsupportedOperationException("Not supported yet."); + throw new LocalizedResourceConfigException("warning.config.selector.invalid_target", object.toString()); + } + + public static PlayerSelector fromMap(Map map, Function, Condition> conditionFactory) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.selector.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + @SuppressWarnings("unchecked") + PlayerSelectorFactory factory = (PlayerSelectorFactory) BuiltInRegistries.PLAYER_SELECTOR_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.selector.invalid_type", type); + } + return factory.create(map, conditionFactory); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java index 978c8ccfd..64024828c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/SelfPlayerSelector.java @@ -1,11 +1,14 @@ package net.momirealms.craftengine.core.plugin.context.selector; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import java.util.List; +import java.util.Map; +import java.util.function.Function; public class SelfPlayerSelector implements PlayerSelector { @@ -18,4 +21,11 @@ public class SelfPlayerSelector implements PlayerSelector implements PlayerSelectorFactory { + @Override + public PlayerSelector create(Map args, Function, Condition> conditionFactory) { + return new SelfPlayerSelector<>(); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java index d2d6d7c4c..b1c578046 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java @@ -28,6 +28,9 @@ public class EventConditions { register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); + register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); + register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); + register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java index 91dc5df2a..91d28760f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java @@ -1,10 +1,7 @@ package net.momirealms.craftengine.core.plugin.event; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; -import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.context.function.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -24,6 +21,10 @@ public class EventFunctions { static { register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.MESSAGE, new MessageFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.ACTIONBAR, new ActionBarFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.TITLE, new TitleFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.CANCEL_EVENT, new CancelEventFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 708f00d80..a28c42fe9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -25,6 +25,7 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectorFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; @@ -54,6 +55,7 @@ public class BuiltInRegistries { public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); public static final Registry> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY); public static final Registry> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY); + public static final Registry> PLAYER_SELECTOR_FACTORY = createRegistry(Registries.PLAYER_SELECTOR_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 5d0ab47b6..5d8ed2868 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -25,6 +25,7 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectorFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; @@ -53,6 +54,7 @@ public class Registries { public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); - public static final ResourceKey>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); + public static final ResourceKey>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory")); + public static final ResourceKey>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory")); + public static final ResourceKey>> PLAYER_SELECTOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_selector")); } From ec2298fe6d43e4d22183e15fa2ffce593166d950 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 15 May 2025 03:17:21 +0800 Subject: [PATCH 63/73] =?UTF-8?q?=E5=A2=9E=E5=BC=BA1.21.2=E7=9A=84item=20m?= =?UTF-8?q?odel=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 4 +- .../bukkit/block/BlockEventListener.java | 10 +-- .../entity/data/InteractionEntityData.java | 1 - .../entity/data/TextDisplayEntityData.java | 1 - .../data/ThrowableItemProjectileData.java | 1 - .../core/pack/AbstractPackManager.java | 83 ++++++++++--------- .../craftengine/core/util/Cancellable.java | 27 ++++++ 7 files changed, 79 insertions(+), 48 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index ac1084288..54e0eaa93 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -310,4 +310,6 @@ warning.config.function.actionbar.missing_actionbar: "Issue found in fil warning.config.function.message.missing_message: "Issue found in file - The config '' is missing the required 'message' argument for 'message' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." -warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." \ No newline at end of file +warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." +warning.config.resource_pack.item_model.conflict: "Failed to generate item model for '' because this item model has been occupied by a vanilla item." +warning.config.resource_pack.item_model.v1_21_2.conflict: "Failed to generate item model(v1.21.2) for ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 070c400b4..31b16f093 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -132,18 +132,17 @@ public class BlockEventListener implements Listener { if (itemInHand != null) { Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isPresent()) { - Cancellable dummy = Cancellable.dummy(); + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); optionalCustomItem.get().execute( PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.POSITION, position) .withParameter(DirectContextParameters.PLAYER, serverPlayer) - .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.EVENT, cancellable) .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) ), EventTrigger.BREAK ); - if (dummy.isCancelled()) { - event.setCancelled(true); + if (cancellable.isCancelled()) { return; } } @@ -166,7 +165,7 @@ public class BlockEventListener implements Listener { } // execute functions - Cancellable cancellable = Cancellable.dummy(); + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.BLOCK_STATE, state) @@ -176,7 +175,6 @@ public class BlockEventListener implements Listener { ); state.owner().value().execute(context, EventTrigger.BREAK); if (cancellable.isCancelled()) { - event.setCancelled(true); return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/InteractionEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/InteractionEntityData.java index 250f58909..c571504aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/InteractionEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/InteractionEntityData.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.entity.data; import net.momirealms.craftengine.core.util.VersionHelper; public class InteractionEntityData extends BaseEntityData { - // Interaction only public static final InteractionEntityData Width = of(8, EntityDataValue.Serializers$FLOAT, 1F); public static final InteractionEntityData Height = of(9, EntityDataValue.Serializers$FLOAT, 1F); public static final InteractionEntityData Responsive = of(10, EntityDataValue.Serializers$BOOLEAN, false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java index 403fbb075..cc3324f6d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.entity.data; import net.momirealms.craftengine.bukkit.util.Reflections; public class TextDisplayEntityData extends DisplayEntityData { - // Text display only public static final DisplayEntityData Text = of(23, EntityDataValue.Serializers$COMPONENT, Reflections.instance$Component$empty); public static final DisplayEntityData LineWidth = of(24, EntityDataValue.Serializers$INT, 200); public static final DisplayEntityData BackgroundColor = of(25, EntityDataValue.Serializers$INT, 0x40000000); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java index 6e40923dc..4575d61aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ThrowableItemProjectileData.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.bukkit.util.Reflections; public class ThrowableItemProjectileData extends BaseEntityData { public static final ThrowableItemProjectileData ItemStack = new ThrowableItemProjectileData<>(8, EntityDataValue.Serializers$ITEM_STACK, Reflections.instance$ItemStack$Air); - public ThrowableItemProjectileData(int id, Object serializer, T defaultValue) { super(id, serializer, defaultValue); } 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 34ead8527..04dc87cdc 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 @@ -560,13 +560,13 @@ public abstract class AbstractPackManager implements PackManager { } this.generateFonts(generatedPackPath); + this.generateItemModels(generatedPackPath, this.plugin.itemManager()); + this.generateItemModels(generatedPackPath, this.plugin.blockManager()); + this.generateBlockOverrides(generatedPackPath); this.generateLegacyItemOverrides(generatedPackPath); this.generateModernItemOverrides(generatedPackPath); this.generateModernItemModels1_21_2(generatedPackPath); this.generateModernItemModels1_21_4(generatedPackPath); - this.generateBlockOverrides(generatedPackPath); - this.generateItemModels(generatedPackPath, this.plugin.itemManager()); - this.generateItemModels(generatedPackPath, this.plugin.blockManager()); this.generateOverrideSounds(generatedPackPath); this.generateCustomSounds(generatedPackPath); this.generateClientLang(generatedPackPath); @@ -911,60 +911,67 @@ public abstract class AbstractPackManager implements PackManager { if (Config.packMaxVersion() < 21.19f) return; if (Config.packMinVersion() > 21.39f) return; - boolean has = false; - for (Map.Entry> entry : plugin.itemManager().modernItemModels1_21_2().entrySet()) { - has = true; - Key key = entry.getKey(); + // 此段代码生成1.21.2专用的item model文件,情况非常复杂! + for (Map.Entry> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) { + Key itemModelPath = entry.getKey(); List legacyOverridesModels = entry.getValue(); - boolean first = true; - JsonObject jsonObject = new JsonObject(); - JsonArray overrides = new JsonArray(); - for (LegacyOverridesModel model : legacyOverridesModels) { - if (first) { - jsonObject.addProperty("parent", model.model()); - if (model.hasPredicate()) { - overrides.add(model.toLegacyPredicateElement()); - } - first = false; - } else { - overrides.add(model.toLegacyPredicateElement()); - } - } - if (!overrides.isEmpty()) { - jsonObject.add("overrides", overrides); + + // 检测item model合法性 + if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) { + TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict", itemModelPath.asString()); + continue; } + // 要检查目标生成路径是否已经存在模型,如果存在模型,应该只为其生成overrides Path itemPath = generatedPackPath .resolve("assets") - .resolve(key.namespace()) + .resolve(itemModelPath.namespace()) .resolve("models") .resolve("item") - .resolve(key.value() + ".json"); - if (Files.exists(itemPath)) { - plugin.logger().warn("Failed to generate item model for [" + key + "] because " + itemPath.toAbsolutePath() + " already exists"); - } else { - if (PRESET_MODERN_MODELS_ITEM.containsKey(key) || PRESET_LEGACY_MODELS_ITEM.containsKey(key)) { - plugin.logger().warn("Failed to generate item model for [" + key + "] because it conflicts with vanilla item"); + .resolve(itemModelPath.value() + ".json"); + + boolean modelExists = Files.exists(itemPath); + JsonObject itemJson; + if (modelExists) { + // 路径已经存在了,那么就应该把模型读入 + try { + itemJson = GsonHelper.readJsonFile(itemPath).getAsJsonObject(); + // 野心真大,已经自己写了overrides,那么不管你了 + if (itemJson.has("overrides")) { + continue; + } + JsonArray overrides = new JsonArray(); + for (LegacyOverridesModel legacyOverridesModel : legacyOverridesModels) { + overrides.add(legacyOverridesModel.toLegacyPredicateElement()); + } + itemJson.add("overrides", overrides); + } catch (IOException e) { + this.plugin.logger().warn("Failed to read item json " + itemPath.toAbsolutePath()); continue; } + } else { + // 如果路径不存在,则需要我们创建一个json对象,并对接model的路径 + itemJson = new JsonObject(); + LegacyOverridesModel firstModel = legacyOverridesModels.getFirst(); + itemJson.addProperty("parent", firstModel.model()); + JsonArray overrides = new JsonArray(); + for (LegacyOverridesModel legacyOverridesModel : legacyOverridesModels) { + overrides.add(legacyOverridesModel.toLegacyPredicateElement()); + } + itemJson.add("overrides", overrides); } try { Files.createDirectories(itemPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + itemPath.toAbsolutePath()); + plugin.logger().severe("Error creating " + itemPath.toAbsolutePath(), e); continue; } try (BufferedWriter writer = Files.newBufferedWriter(itemPath)) { - GsonHelper.get().toJson(jsonObject, writer); + GsonHelper.get().toJson(itemJson, writer); } catch (IOException e) { - plugin.logger().warn("Failed to save item model for [" + key + "]"); + plugin.logger().warn("Failed to save item model for " + itemModelPath, e); } } - - // TODO it later -// if (Config.packMinVersion() < 21.19f && has) { -// plugin.logger().warn("You are using 'item-model' component for some models which requires 1.21.2+ client. But the min-supported-version set in 'config.yml' is " + "1." + Config.packMinVersion()); -// } } private void generateModernItemModels1_21_4(Path generatedPackPath) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java b/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java index 314ad9ce3..91452fc33 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Cancellable.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.util; +import java.util.function.Consumer; +import java.util.function.Supplier; + public interface Cancellable { boolean isCancelled(); @@ -10,6 +13,10 @@ public interface Cancellable { return new Dummy(); } + static Cancellable of(Supplier isCancelled, Consumer setCancelled) { + return new Simple(isCancelled, setCancelled); + } + class Dummy implements Cancellable { private boolean cancelled; @@ -23,4 +30,24 @@ public interface Cancellable { this.cancelled = cancel; } } + + class Simple implements Cancellable { + private final Supplier isCancelled; + private final Consumer setCancelled; + + public Simple(Supplier isCancelled, Consumer setCancelled) { + this.isCancelled = isCancelled; + this.setCancelled = setCancelled; + } + + @Override + public boolean isCancelled() { + return this.isCancelled.get(); + } + + @Override + public void setCancelled(boolean cancel) { + this.setCancelled.accept(cancel); + } + } } From 63a4193f36608f27b9f822961261c7f5ac39a05b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 15 May 2025 03:32:27 +0800 Subject: [PATCH 64/73] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 5 +- .../core/pack/AbstractPackManager.java | 96 +++++++++---------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 54e0eaa93..2a6d99bac 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -311,5 +311,6 @@ warning.config.function.message.missing_message: "Issue found in file Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." -warning.config.resource_pack.item_model.conflict: "Failed to generate item model for '' because this item model has been occupied by a vanilla item." -warning.config.resource_pack.item_model.v1_21_2.conflict: "Failed to generate item model(v1.21.2) for ''." \ No newline at end of file +warning.config.resource_pack.item_model.conflict.vanilla: "Failed to generate item model for '' because this item model has been occupied by a vanilla item." +warning.config.resource_pack.item_model.already_exist: "Failed to generate item model for '' because the file '' already exists." +warning.config.resource_pack.model.generation.already_exist: "Failed to generate model because the model file '' already exists." \ No newline at end of file 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 04dc87cdc..9f23ff855 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 @@ -588,16 +588,16 @@ public abstract class AbstractPackManager implements PackManager { private void generateParticle(Path generatedPackPath) { if (!Config.removeTintedLeavesParticle()) return; if (Config.packMaxVersion() < 21.49f) return; - var json = new JsonObject(); - var textures = new JsonArray(); + JsonObject particleJson = new JsonObject(); + JsonArray textures = new JsonArray(); textures.add("empty"); - json.add("textures", textures); - var jsonPath = generatedPackPath + particleJson.add("textures", textures); + Path jsonPath = generatedPackPath .resolve("assets") .resolve("minecraft") .resolve("particles") .resolve("tinted_leaves.json"); - var pngPath = generatedPackPath + Path pngPath = generatedPackPath .resolve("assets") .resolve("minecraft") .resolve("textures") @@ -607,11 +607,11 @@ public abstract class AbstractPackManager implements PackManager { Files.createDirectories(jsonPath.getParent()); Files.createDirectories(pngPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating directories", e); + this.plugin.logger().severe("Error creating directories", e); return; } try { - GsonHelper.writeJsonFile(json, jsonPath); + GsonHelper.writeJsonFile(particleJson, jsonPath); Files.write(pngPath, EMPTY_IMAGE); } catch (IOException e) { this.plugin.logger().severe("Error writing particles file", e); @@ -822,19 +822,16 @@ public abstract class AbstractPackManager implements PackManager { .resolve(generation.path().namespace()) .resolve("models") .resolve(generation.path().value() + ".json"); - if (Files.exists(modelPath)) { - plugin.logger().warn("Failed to generate model because " + modelPath.toAbsolutePath() + " already exists"); + TranslationManager.instance().log("warning.config.resource_pack.model.generation.already_exist", modelPath.toAbsolutePath().toString()); continue; } - try { Files.createDirectories(modelPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + modelPath.toAbsolutePath()); + plugin.logger().severe("Error creating " + modelPath.toAbsolutePath(), e); continue; } - try (BufferedWriter writer = Files.newBufferedWriter(modelPath)) { GsonHelper.get().toJson(generation.get(), writer); } catch (IOException e) { @@ -871,13 +868,13 @@ public abstract class AbstractPackManager implements PackManager { try { Files.createDirectories(overridedBlockPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + overridedBlockPath.toAbsolutePath()); + plugin.logger().severe("Error creating " + overridedBlockPath.toAbsolutePath(), e); continue; } try (BufferedWriter writer = Files.newBufferedWriter(overridedBlockPath)) { GsonHelper.get().toJson(stateJson, writer); } catch (IOException e) { - plugin.logger().warn("Failed to create block states for [" + key + "]"); + plugin.logger().warn("Failed to create block states for " + key, e); } } @@ -896,13 +893,13 @@ public abstract class AbstractPackManager implements PackManager { try { Files.createDirectories(overridedBlockPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + overridedBlockPath.toAbsolutePath()); + plugin.logger().severe("Error creating " + overridedBlockPath.toAbsolutePath(), e); continue; } try (BufferedWriter writer = Files.newBufferedWriter(overridedBlockPath)) { GsonHelper.get().toJson(stateJson, writer); } catch (IOException e) { - plugin.logger().warn("Failed to create block states for [" + key + "]"); + plugin.logger().warn("Failed to create block states for " + key, e); } } } @@ -918,7 +915,7 @@ public abstract class AbstractPackManager implements PackManager { // 检测item model合法性 if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) { - TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict", itemModelPath.asString()); + TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict.vanilla", itemModelPath.asString()); continue; } @@ -976,25 +973,26 @@ public abstract class AbstractPackManager implements PackManager { private void generateModernItemModels1_21_4(Path generatedPackPath) { if (Config.packMaxVersion() < 21.39f) return; - for (Map.Entry entry : plugin.itemManager().modernItemModels1_21_4().entrySet()) { + for (Map.Entry entry : this.plugin.itemManager().modernItemModels1_21_4().entrySet()) { Key key = entry.getKey(); Path itemPath = generatedPackPath .resolve("assets") .resolve(key.namespace()) .resolve("items") .resolve(key.value() + ".json"); + + if (PRESET_ITEMS.containsKey(key)) { + TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict.vanilla", key.asString()); + continue; + } if (Files.exists(itemPath)) { - plugin.logger().warn("Failed to generate item model for [" + key + "] because " + itemPath.toAbsolutePath() + " already exists"); - } else { - if (PRESET_ITEMS.containsKey(key)) { - plugin.logger().warn("Failed to generate item model for [" + key + "] because it conflicts with vanilla item"); - continue; - } + TranslationManager.instance().log("warning.config.resource_pack.item_model.already_exist", key.asString(), itemPath.toAbsolutePath().toString()); + continue; } try { Files.createDirectories(itemPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + itemPath.toAbsolutePath()); + this.plugin.logger().severe("Error creating " + itemPath.toAbsolutePath(), e); continue; } JsonObject model = new JsonObject(); @@ -1002,40 +1000,39 @@ public abstract class AbstractPackManager implements PackManager { try (BufferedWriter writer = Files.newBufferedWriter(itemPath)) { GsonHelper.get().toJson(model, writer); } catch (IOException e) { - plugin.logger().warn("Failed to save item model for [" + key + "]"); + this.plugin.logger().warn("Failed to save item model for " + key, e); } } } private void generateModernItemOverrides(Path generatedPackPath) { if (Config.packMaxVersion() < 21.39f) return; - for (Map.Entry> entry : plugin.itemManager().modernItemOverrides().entrySet()) { - Key key = entry.getKey(); + for (Map.Entry> entry : this.plugin.itemManager().modernItemOverrides().entrySet()) { + Key vanillaItemModel = entry.getKey(); Path overridedItemPath = generatedPackPath .resolve("assets") - .resolve(key.namespace()) + .resolve(vanillaItemModel.namespace()) .resolve("items") - .resolve(key.value() + ".json"); + .resolve(vanillaItemModel.value() + ".json"); JsonObject originalItemModel; if (Files.exists(overridedItemPath)) { try { originalItemModel = GsonHelper.readJsonFile(overridedItemPath).getAsJsonObject(); } catch (IOException e) { - plugin.logger().warn("Failed to load existing item model (modern)", e); + this.plugin.logger().warn("Failed to load existing item model (modern)", e); continue; } } else { - originalItemModel = PRESET_ITEMS.get(key); + originalItemModel = PRESET_ITEMS.get(vanillaItemModel); if (originalItemModel == null) { - plugin.logger().warn("Failed to load existing item model for [" + key + "] (modern)"); + this.plugin.logger().warn("Failed to load existing item model for " + vanillaItemModel + " (modern)"); continue; } } boolean handAnimationOnSwap = Optional.ofNullable(originalItemModel.get("hand_animation_on_swap")).map(JsonElement::getAsBoolean).orElse(true); JsonObject fallbackModel = originalItemModel.get("model").getAsJsonObject(); - JsonObject newJson = new JsonObject(); JsonObject model = new JsonObject(); newJson.add("model", model); @@ -1044,6 +1041,7 @@ public abstract class AbstractPackManager implements PackManager { if (!handAnimationOnSwap) { model.addProperty("hand_animation_on_swap", false); } + // 将原有的json读成fallback model.add("fallback", fallbackModel); JsonArray entries = new JsonArray(); model.add("entries", entries); @@ -1056,43 +1054,42 @@ public abstract class AbstractPackManager implements PackManager { try { Files.createDirectories(overridedItemPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + overridedItemPath.toAbsolutePath()); + this.plugin.logger().severe("Error creating " + overridedItemPath.toAbsolutePath(), e); continue; } try (BufferedWriter writer = Files.newBufferedWriter(overridedItemPath)) { GsonHelper.get().toJson(newJson, writer); } catch (IOException e) { - plugin.logger().warn("Failed to save item model for [" + key + "]"); + this.plugin.logger().warn("Failed to save item model for " + vanillaItemModel, e); } } } private void generateLegacyItemOverrides(Path generatedPackPath) { if (Config.packMinVersion() > 21.39f) return; - for (Map.Entry> entry : plugin.itemManager().legacyItemOverrides().entrySet()) { - Key key = entry.getKey(); + for (Map.Entry> entry : this.plugin.itemManager().legacyItemOverrides().entrySet()) { + Key vanillaLegacyModel = entry.getKey(); Path overridedItemPath = generatedPackPath .resolve("assets") - .resolve(key.namespace()) + .resolve(vanillaLegacyModel.namespace()) .resolve("models") .resolve("item") - .resolve(key.value() + ".json"); + .resolve(vanillaLegacyModel.value() + ".json"); JsonObject originalItemModel; if (Files.exists(overridedItemPath)) { try (BufferedReader reader = Files.newBufferedReader(overridedItemPath)) { originalItemModel = JsonParser.parseReader(reader).getAsJsonObject(); } catch (IOException e) { - plugin.logger().warn("Failed to load existing item model (legacy)", e); + this.plugin.logger().warn("Failed to load existing item model (legacy)", e); continue; } } else { - originalItemModel = PRESET_LEGACY_MODELS_ITEM.get(key); - } - if (originalItemModel == null) { - plugin.logger().warn("Failed to load item model for [" + key + "] (legacy)"); - continue; - } else { + originalItemModel = PRESET_LEGACY_MODELS_ITEM.get(vanillaLegacyModel); + if (originalItemModel == null) { + this.plugin.logger().warn("Failed to load item model for " + vanillaLegacyModel + " (legacy)"); + continue; + } originalItemModel = originalItemModel.deepCopy(); } JsonArray overrides; @@ -1109,14 +1106,13 @@ public abstract class AbstractPackManager implements PackManager { try { Files.createDirectories(overridedItemPath.getParent()); } catch (IOException e) { - plugin.logger().severe("Error creating " + overridedItemPath.toAbsolutePath()); + plugin.logger().severe("Error creating " + overridedItemPath.toAbsolutePath(), e); continue; } - try (BufferedWriter writer = Files.newBufferedWriter(overridedItemPath)) { GsonHelper.get().toJson(originalItemModel, writer); } catch (IOException e) { - plugin.logger().warn("Failed to save item model for [" + key + "]"); + plugin.logger().warn("Failed to save item model for " + vanillaLegacyModel, e); } } } From ce4001ea8afc86846088ca8190922ce009466e1b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 15 May 2025 19:10:18 +0800 Subject: [PATCH 65/73] =?UTF-8?q?=E5=8A=A0=E5=BF=AB=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 3 + .../core/pack/AbstractPackManager.java | 68 +++++++++++-------- .../core/pack/CachedConfigFile.java | 27 ++++++++ .../craftengine/core/util/FileUtils.java | 25 +++++++ gradle.properties | 2 +- 5 files changed, 95 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.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 c4d9295ab..5210f9e4a 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 @@ -365,6 +365,8 @@ public class BukkitItemManager extends AbstractItemManager { // cache command suggestions cachedSuggestions.add(Suggestion.suggestion(id.toString())); + + // TODO Deprecated 理论支持任意物品类型 if (material == Material.TOTEM_OF_UNDYING) cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); @@ -426,6 +428,7 @@ public class BukkitItemManager extends AbstractItemManager { } if (Config.packMinVersion() < 21.39f) { + // TODO 手动指定旧版格式 List legacyOverridesModels = new ArrayList<>(); processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); TreeSet lom = legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); 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 9f23ff855..c56a144cf 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 @@ -71,10 +71,11 @@ public abstract class AbstractPackManager implements PackManager { private final BiConsumer eventDispatcher; private final Map loadedPacks = new HashMap<>(); private final Map sectionParsers = new HashMap<>(); - private final TreeMap> cachedConfigs = new TreeMap<>(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; + private Map cachedConfigFiles = Collections.emptyMap(); + public AbstractPackManager(CraftEngine plugin, BiConsumer eventDispatcher) { this.plugin = plugin; this.eventDispatcher = eventDispatcher; @@ -175,7 +176,6 @@ public abstract class AbstractPackManager implements PackManager { @Override public void unload() { this.loadedPacks.clear(); - this.cachedConfigs.clear(); } @Override @@ -408,38 +408,48 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); } - private void loadResourceConfigs(Predicate predicate) { - long o1 = System.nanoTime(); + private void updateCachedConfigFiles() { + Map previousFiles = this.cachedConfigFiles; + this.cachedConfigFiles = new HashMap<>(); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; - Pair, List> files = FileUtils.getConfigsDeeply(pack.configurationFolder()); - for (Path path : files.left()) { - try (InputStreamReader inputStream = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) { - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); - Map data = yaml.load(inputStream); - if (data == null) continue; - for (Map.Entry entry : data.entrySet()) { - processConfigEntry(entry, path, pack); + List files = FileUtils.getYmlConfigsDeeply(pack.configurationFolder()); + for (Path path : files) { + CachedConfigFile cachedFile = previousFiles.get(path); + try { + long lastModifiedTime = Files.getLastModifiedTime(path).toMillis(); + if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime) { + this.cachedConfigFiles.put(path, cachedFile); + continue; } - } catch (Exception e) { - this.plugin.logger().warn(path, "Error loading config file", e); + try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); + Map data = yaml.load(inputStream); + this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime)); + } catch (Exception e) { + this.plugin.logger().warn(path, "Error loading config file", e); + } + } catch (IOException e) { + this.plugin.logger().warn(path, "Error reading last modified time", e); } } - for (Path path : files.right()) { - try (InputStreamReader inputStream = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) { - Map dataRaw = GsonHelper.get().fromJson(JsonParser.parseReader(inputStream).getAsJsonObject(), Map.class); - Map data = castToMap(dataRaw, false); - for (Map.Entry entry : data.entrySet()) { - processConfigEntry(entry, path, pack); - } - } catch (Exception e) { - this.plugin.logger().warn(path, "Error loading config file", e); - } + } + } + + private void loadResourceConfigs(Predicate predicate) { + TreeMap> cachedConfigs = new TreeMap<>(); + long o1 = System.nanoTime(); + this.updateCachedConfigFiles(); + for (Map.Entry fileEntry : this.cachedConfigFiles.entrySet()) { + CachedConfigFile cachedFile = fileEntry.getValue(); + for (Map.Entry entry : cachedFile.config().entrySet()) { + processConfigEntry(entry, fileEntry.getKey(), cachedFile.pack(), (p, c) -> + cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)); } } long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); - for (Map.Entry> entry : this.cachedConfigs.entrySet()) { + for (Map.Entry> entry : cachedConfigs.entrySet()) { ConfigParser parser = entry.getKey(); long t1 = System.nanoTime(); for (CachedConfig cached : entry.getValue()) { @@ -476,17 +486,17 @@ public abstract class AbstractPackManager implements PackManager { long t2 = System.nanoTime(); this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } - this.cachedConfigs.clear(); } - private void processConfigEntry(Map.Entry entry, Path path, Pack pack) { + private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); int hashIndex = key.indexOf('#'); String configType = hashIndex != -1 ? key.substring(0, hashIndex) : key; Optional.ofNullable(this.sectionParsers.get(configType)) - .ifPresent(parser -> this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>()) - .add(new CachedConfig(key, castToMap(typeSections0, false), path, pack))); + .ifPresent(parser -> { + callback.accept(parser, new CachedConfig(key, castToMap(typeSections0, false), path, pack)); + }); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java new file mode 100644 index 000000000..c39cf4e36 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.pack; + +import java.util.Map; + +public class CachedConfigFile { + private final Map config; + private final long lastModified; + private final Pack pack; + + public CachedConfigFile(Map config, Pack pack, long lastModified) { + this.config = config; + this.lastModified = lastModified; + this.pack = pack; + } + + public Pack pack() { + return pack; + } + + public Map config() { + return config; + } + + public long lastModified() { + return lastModified; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 0e8889039..a4aec22f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -22,6 +22,31 @@ public class FileUtils { Files.createDirectories(Files.exists(path) ? path.toRealPath() : path); } + public static List getYmlConfigsDeeply(Path configFolder) { + if (!Files.exists(configFolder)) return List.of(); + List validYaml = new ArrayList<>(); + Deque pathDeque = new ArrayDeque<>(); + pathDeque.push(configFolder); + while (!pathDeque.isEmpty()) { + Path path = pathDeque.pop(); + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path subPath : stream) { + if (Files.isDirectory(subPath)) { + pathDeque.push(subPath); + } else if (Files.isRegularFile(subPath)) { + String pathString = subPath.toString(); + if (pathString.endsWith(".yml")) { + validYaml.add(subPath); + } + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return validYaml; + } + public static Pair, List> getConfigsDeeply(Path configFolder) { if (!Files.exists(configFolder)) return Pair.of(List.of(), List.of()); List validYaml = new ArrayList<>(); diff --git a/gradle.properties b/gradle.properties index 8a3975c14..6f6eab7d6 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.53.7 +project_version=0.0.53.8 config_version=32 lang_version=12 project_group=net.momirealms From aef55f0cf0978b9eb972e5359a11097a87083406 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 16 May 2025 03:12:43 +0800 Subject: [PATCH 66/73] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=99=9A=E6=8B=9F?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 1 + bukkit/loader/build.gradle.kts | 1 + .../main/resources/craft-engine.properties | 3 +- core/build.gradle.kts | 3 + .../core/pack/AbstractPackManager.java | 112 +++++++++--------- .../craftengine/core/plugin/CraftEngine.java | 3 +- .../core/plugin/dependency/Dependencies.java | 8 ++ gradle.properties | 15 +-- 8 files changed, 81 insertions(+), 65 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 8e5ae6b27..a4e5f7f9c 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -95,6 +95,7 @@ tasks { relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") + relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 6be000e1a..f0deeb5a6 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -78,5 +78,6 @@ tasks { relocate("net.jpountz", "net.momirealms.craftengine.libraries.jpountz") relocate("software.amazon.awssdk", "net.momirealms.craftengine.libraries.awssdk") relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") + relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") } } diff --git a/bukkit/loader/src/main/resources/craft-engine.properties b/bukkit/loader/src/main/resources/craft-engine.properties index c94d83fa0..9a8362d82 100644 --- a/bukkit/loader/src/main/resources/craft-engine.properties +++ b/bukkit/loader/src/main/resources/craft-engine.properties @@ -33,4 +33,5 @@ netty-codec-http2=${netty_version} reactive-streams=${reactive_streams_version} amazon-sdk-s3=${amazon_awssdk_version} amazon-sdk-eventstream=${amazon_awssdk_eventstream_version} -evalex=${evalex_version} \ No newline at end of file +evalex=${evalex_version} +jimfs=${jimfs_version} \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 8b6a644d8..51fe3f5e3 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -56,6 +56,8 @@ dependencies { compileOnly("software.amazon.awssdk:netty-nio-client:${rootProject.properties["amazon_awssdk_version"]}") // EvalEx compileOnly("com.ezylang:EvalEx:${rootProject.properties["evalex_version"]}") + // Jimfs + compileOnly("com.google.jimfs:jimfs:${rootProject.properties["jimfs_version"]}") } java { @@ -88,6 +90,7 @@ tasks { relocate("software.amazon.awssdk", "net.momirealms.craftengine.libraries.awssdk") // awssdk relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") // awssdk relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") + relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") } } 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 c56a144cf..ad4625158 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,5 +1,7 @@ package net.momirealms.craftengine.core.pack; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import com.google.gson.*; import dev.dejvokep.boostedyaml.YamlDocument; import dev.dejvokep.boostedyaml.block.implementation.Section; @@ -535,64 +537,57 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Generating resource pack..."); long start = System.currentTimeMillis(); // get the target location - Path generatedPackPath = this.plugin.dataFolderPath() - .resolve("generated") - .resolve("resource_pack"); - - try { - deleteDirectory(generatedPackPath); - } catch (IOException e) { - this.plugin.logger().severe("Error deleting previous resource pack", e); - } - - // firstly merge existing folders - try { - List folders = new ArrayList<>(); - folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); - folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); - List>> duplicated = mergeFolder(folders, generatedPackPath); - if (!duplicated.isEmpty()) { - plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); - int x = 1; - for (Pair> path : duplicated) { - this.plugin.logger().warn("[ " + (x++) + " ] " + path.left()); - for (int i = 0, size = path.right().size(); i < size; i++) { - if (i == size - 1) { - this.plugin.logger().info(" └ " + path.right().get(i).toAbsolutePath()); - } else { - this.plugin.logger().info(" ├ " + path.right().get(i).toAbsolutePath()); + try (FileSystem fs = Jimfs.newFileSystem(Configuration.forCurrentPlatform())) { + // firstly merge existing folders + try { + Path generatedPackPath = fs.getPath("resource_pack"); + List folders = new ArrayList<>(); + folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); + folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); + List>> duplicated = mergeFolder(folders, fs); + if (!duplicated.isEmpty()) { + plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); + int x = 1; + for (Pair> path : duplicated) { + this.plugin.logger().warn("[ " + (x++) + " ] " + path.left()); + for (int i = 0, size = path.right().size(); i < size; i++) { + if (i == size - 1) { + this.plugin.logger().info(" └ " + path.right().get(i).toAbsolutePath()); + } else { + this.plugin.logger().info(" ├ " + path.right().get(i).toAbsolutePath()); + } } } } + + this.generateFonts(generatedPackPath); + this.generateItemModels(generatedPackPath, this.plugin.itemManager()); + this.generateItemModels(generatedPackPath, this.plugin.blockManager()); + this.generateBlockOverrides(generatedPackPath); + this.generateLegacyItemOverrides(generatedPackPath); + this.generateModernItemOverrides(generatedPackPath); + this.generateModernItemModels1_21_2(generatedPackPath); + this.generateModernItemModels1_21_4(generatedPackPath); + this.generateOverrideSounds(generatedPackPath); + this.generateCustomSounds(generatedPackPath); + this.generateClientLang(generatedPackPath); + this.generateEquipments(generatedPackPath); + this.generateParticle(generatedPackPath); + Path zipFile = resourcePackPath(); + try { + this.zipGenerator.accept(generatedPackPath, zipFile); + } catch (Exception e) { + this.plugin.logger().severe("Error zipping resource pack", e); + } + long end = System.currentTimeMillis(); + this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); + this.eventDispatcher.accept(generatedPackPath, zipFile); + } catch (Exception e) { + this.plugin.logger().severe("Error merging resource pack", e); } } catch (IOException e) { - this.plugin.logger().severe("Error merging resource pack", e); + throw new RuntimeException(e); } - - this.generateFonts(generatedPackPath); - this.generateItemModels(generatedPackPath, this.plugin.itemManager()); - this.generateItemModels(generatedPackPath, this.plugin.blockManager()); - this.generateBlockOverrides(generatedPackPath); - this.generateLegacyItemOverrides(generatedPackPath); - this.generateModernItemOverrides(generatedPackPath); - this.generateModernItemModels1_21_2(generatedPackPath); - this.generateModernItemModels1_21_4(generatedPackPath); - this.generateOverrideSounds(generatedPackPath); - this.generateCustomSounds(generatedPackPath); - this.generateClientLang(generatedPackPath); - this.generateEquipments(generatedPackPath); - this.generateParticle(generatedPackPath); - - Path zipFile = resourcePackPath(); - try { - this.zipGenerator.accept(generatedPackPath, zipFile); - } catch (Exception e) { - this.plugin.logger().severe("Error zipping resource pack", e); - } - - long end = System.currentTimeMillis(); - this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); - this.eventDispatcher.accept(generatedPackPath, zipFile); } private void generateParticle(Path generatedPackPath) { @@ -1166,11 +1161,16 @@ public abstract class AbstractPackManager implements PackManager { providers.add(image.get()); } - try (FileWriter fileWriter = new FileWriter(fontPath.toFile())) { - fileWriter.write(fontJson.toString().replace("\\\\u", "\\u")); + try { + Files.writeString(fontPath, fontJson.toString().replace("\\\\u", "\\u")); } catch (IOException e) { throw new RuntimeException(e); } +// try (FileWriter fileWriter = new FileWriter(fontPath.toFile())) { +// fileWriter.write(fontJson.toString().replace("\\\\u", "\\u")); +// } catch (IOException e) { +// throw new RuntimeException(e); +// } } if (Config.resourcePack$overrideUniform()) { @@ -1192,7 +1192,7 @@ public abstract class AbstractPackManager implements PackManager { } } - private List>> mergeFolder(Collection sourceFolders, Path targetFolder) throws IOException { + private List>> mergeFolder(Collection sourceFolders, FileSystem fs) throws IOException { Map> conflictChecker = new HashMap<>(); for (Path sourceFolder : sourceFolders) { if (Files.exists(sourceFolder)) { @@ -1200,7 +1200,7 @@ public abstract class AbstractPackManager implements PackManager { @Override public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { Path relative = sourceFolder.relativize(file); - Path targetPath = targetFolder.resolve(relative); + Path targetPath = fs.getPath("resource_pack/" + relative.toString().replace("\\", "/")); List conflicts = conflictChecker.computeIfAbsent(relative, k -> new ArrayList<>()); if (conflicts.isEmpty()) { Files.createDirectories(targetPath.getParent()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 59d86f55d..57ba00ab6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -309,7 +309,8 @@ public abstract class CraftEngine implements Plugin { Dependencies.TEXT_SERIALIZER_GSON, Dependencies.TEXT_SERIALIZER_GSON_LEGACY, Dependencies.TEXT_SERIALIZER_JSON, Dependencies.AHO_CORASICK, Dependencies.LZ4, - Dependencies.EVALEX + Dependencies.EVALEX, + Dependencies.JIMFS ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java index 285430f15..31e274fdc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java @@ -280,6 +280,14 @@ public class Dependencies { List.of(Relocation.of("reactivestreams", "org{}reactivestreams")) ); + public static final Dependency JIMFS = new Dependency( + "jimfs", + "com{}google{}jimfs", + "jimfs", + "jimfs", + List.of(Relocation.of("jimfs", "com{}google{}common{}jimfs")) + ); + public static final Dependency AMAZON_AWSSDK_S3 = new Dependency( "amazon-sdk-s3", "software{}amazon{}awssdk", diff --git a/gradle.properties b/gradle.properties index 6f6eab7d6..ddf001944 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.53.8 +project_version=0.0.53.9 config_version=32 lang_version=12 project_group=net.momirealms @@ -55,6 +55,7 @@ evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 amazon_awssdk_eventstream_version=1.0.1 +jimfs_version=1.3.0 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7 @@ -69,9 +70,9 @@ modmenu_version=13.0.3 cloth_version=17.0.144 # Proxy settings -#systemProp.socks.proxyHost=127.0.0.1 -#systemProp.socks.proxyPort=7890 -#systemProp.http.proxyHost=127.0.0.1 -#systemProp.http.proxyPort=7890 -#systemProp.https.proxyHost=127.0.0.1 -#systemProp.https.proxyPort=7890 \ No newline at end of file +systemProp.socks.proxyHost=127.0.0.1 +systemProp.socks.proxyPort=7890 +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7890 \ No newline at end of file From 804c8f6c807f0d74a4ca764c6144b853f098b6a1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 16 May 2025 03:29:40 +0800 Subject: [PATCH 67/73] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ddf001944..20e20af38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 sparrow_nbt_version=0.7.3 -sparrow_util_version=0.40 +sparrow_util_version=0.42 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From 1eb64ba0b6a997b71d28cdfa8aa0f2ddbd8bef98 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 16 May 2025 20:31:57 +0800 Subject: [PATCH 68/73] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E5=8C=85=E7=94=9F=E6=88=90=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 1 + bukkit/loader/build.gradle.kts | 1 + .../main/resources/craft-engine.properties | 1 + .../plugin/command/feature/ReloadCommand.java | 4 +- core/build.gradle.kts | 1 + .../core/pack/AbstractPackManager.java | 171 +++++++++--------- .../craftengine/core/pack/PackManager.java | 3 +- .../craftengine/core/plugin/CraftEngine.java | 3 +- .../core/plugin/dependency/Dependencies.java | 8 + gradle.properties | 3 +- 10 files changed, 102 insertions(+), 94 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index a4e5f7f9c..0b9d4ae93 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -96,6 +96,7 @@ tasks { relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") + relocate("org.apache.commons.imaging", "net.momirealms.craftengine.libraries.imaging") } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index f0deeb5a6..5085f47dc 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -79,5 +79,6 @@ tasks { relocate("software.amazon.awssdk", "net.momirealms.craftengine.libraries.awssdk") relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") + relocate("org.apache.commons.imaging", "net.momirealms.craftengine.libraries.imaging") } } diff --git a/bukkit/loader/src/main/resources/craft-engine.properties b/bukkit/loader/src/main/resources/craft-engine.properties index 9a8362d82..9e875e126 100644 --- a/bukkit/loader/src/main/resources/craft-engine.properties +++ b/bukkit/loader/src/main/resources/craft-engine.properties @@ -20,6 +20,7 @@ caffeine=${caffeine_version} slf4j-api=${slf4j_version} zstd-jni=${zstd_version} commons-io=${commons_io_version} +commons-imaging=${commons_imaging_version} byte-buddy=${byte_buddy_version} snake-yaml=${snake_yaml_version} adventure-text-minimessage=${adventure_bundle_version} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index db8d277a1..c3ab26bd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -54,7 +54,6 @@ public class ReloadCommand extends BukkitCommandFeature { Component.text(reloadResult.asyncTime()), Component.text(reloadResult.syncTime()) ); - }); } catch (Exception e) { handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); @@ -88,6 +87,9 @@ public class ReloadCommand extends BukkitCommandFeature { Component.text(reloadResult.syncTime()), Component.text(packTime) ); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); } finally { RELOAD_PACK_FLAG = false; } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 51fe3f5e3..c577bb564 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -91,6 +91,7 @@ tasks { relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") // awssdk relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") + relocate("org.apache.commons.imaging", "net.momirealms.craftengine.libraries.imaging") } } 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 ad4625158..ebcd6caa5 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 @@ -19,6 +19,7 @@ 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; @@ -46,7 +47,6 @@ import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Stream; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; @@ -145,7 +145,6 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { - initFileSystemProvider(); List> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting"); if (list == null || list.isEmpty()) { this.resourcePackHost = NoneHost.INSTANCE; @@ -187,12 +186,13 @@ public abstract class AbstractPackManager implements PackManager { if (magicClazz != null) { int fileCount = ObfA.VALUES[1] - ObfA.VALUES[17]; Constructor magicConstructor = ReflectionUtils.getConstructor(magicClazz, fileCount); + assert magicConstructor != null; +// magicConstructor.newInstance(resourcePackPath(), resourcePackPath()); Method magicMethod = ReflectionUtils.getMethod(magicClazz, void.class); + assert magicMethod != null; this.zipGenerator = (p1, p2) -> { try { - assert magicConstructor != null; Object magicObject = magicConstructor.newInstance(p1, p2); - assert magicMethod != null; magicMethod.invoke(magicObject); } catch (Exception e) { this.plugin.logger().warn("Failed to generate zip files", e); @@ -427,6 +427,7 @@ public abstract class AbstractPackManager implements PackManager { try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); Map data = yaml.load(inputStream); + if (data == null) continue; this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime)); } catch (Exception e) { this.plugin.logger().warn(path, "Error loading config file", e); @@ -502,91 +503,92 @@ public abstract class AbstractPackManager implements PackManager { } } - private static void initFileSystemProvider() { - String osName = System.getProperty("os.name").toLowerCase(); - String providerClass = null; - if (osName.contains("win")) { - providerClass = "sun.nio.fs.WindowsFileSystemProvider"; - } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { - providerClass = "sun.nio.fs.LinuxFileSystemProvider"; - } else if (osName.contains("mac")) { - providerClass = "sun.nio.fs.MacOSXFileSystemProvider"; - } - if (providerClass != null) { - try { - System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", providerClass); - } catch (Exception ignored) {} - } - } +// private static void initFileSystemProvider() { +// String osName = System.getProperty("os.name").toLowerCase(); +// String providerClass = null; +// if (osName.contains("win")) { +// providerClass = "sun.nio.fs.WindowsFileSystemProvider"; +// } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { +// providerClass = "sun.nio.fs.LinuxFileSystemProvider"; +// } else if (osName.contains("mac")) { +// providerClass = "sun.nio.fs.MacOSXFileSystemProvider"; +// } +// if (providerClass != null) { +// try { +// System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", providerClass); +// } catch (Exception ignored) {} +// } +// } +// +// private static void deleteDirectory(Path folder) throws IOException { +// if (!Files.exists(folder)) return; +// try (Stream walk = Files.walk(folder)) { +// walk.sorted(Comparator.reverseOrder()) +// .parallel() +// .forEach(path -> { +// try { +// Files.delete(path); +// } catch (IOException ignored) {} +// }); +// } +// } + + private void updateAssetsCache(List folders) { - private static void deleteDirectory(Path folder) throws IOException { - if (!Files.exists(folder)) return; - try (Stream walk = Files.walk(folder)) { - walk.sorted(Comparator.reverseOrder()) - .parallel() - .forEach(path -> { - try { - Files.delete(path); - } catch (IOException ignored) {} - }); - } } @Override - public void generateResourcePack() { + public void generateResourcePack() throws IOException { this.plugin.logger().info("Generating resource pack..."); long start = System.currentTimeMillis(); // get the target location try (FileSystem fs = Jimfs.newFileSystem(Configuration.forCurrentPlatform())) { // firstly merge existing folders - try { - Path generatedPackPath = fs.getPath("resource_pack"); - List folders = new ArrayList<>(); - folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); - folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); - List>> duplicated = mergeFolder(folders, fs); - if (!duplicated.isEmpty()) { - plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); - int x = 1; - for (Pair> path : duplicated) { - this.plugin.logger().warn("[ " + (x++) + " ] " + path.left()); - for (int i = 0, size = path.right().size(); i < size; i++) { - if (i == size - 1) { - this.plugin.logger().info(" └ " + path.right().get(i).toAbsolutePath()); - } else { - this.plugin.logger().info(" ├ " + path.right().get(i).toAbsolutePath()); - } + Path generatedPackPath = fs.getPath("resource_pack"); + List folders = new ArrayList<>(); + folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); + folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); + List>> duplicated = mergeFolder(folders, fs); + if (!duplicated.isEmpty()) { + plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); + int x = 1; + for (Pair> path : duplicated) { + this.plugin.logger().warn("[ " + (x++) + " ] " + path.left()); + for (int i = 0, size = path.right().size(); i < size; i++) { + if (i == size - 1) { + this.plugin.logger().info(" └ " + path.right().get(i).toAbsolutePath()); + } else { + this.plugin.logger().info(" ├ " + path.right().get(i).toAbsolutePath()); } } } - - this.generateFonts(generatedPackPath); - this.generateItemModels(generatedPackPath, this.plugin.itemManager()); - this.generateItemModels(generatedPackPath, this.plugin.blockManager()); - this.generateBlockOverrides(generatedPackPath); - this.generateLegacyItemOverrides(generatedPackPath); - this.generateModernItemOverrides(generatedPackPath); - this.generateModernItemModels1_21_2(generatedPackPath); - this.generateModernItemModels1_21_4(generatedPackPath); - this.generateOverrideSounds(generatedPackPath); - this.generateCustomSounds(generatedPackPath); - this.generateClientLang(generatedPackPath); - this.generateEquipments(generatedPackPath); - this.generateParticle(generatedPackPath); - Path zipFile = resourcePackPath(); - try { - this.zipGenerator.accept(generatedPackPath, zipFile); - } catch (Exception e) { - this.plugin.logger().severe("Error zipping resource pack", e); - } - long end = System.currentTimeMillis(); - this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); - this.eventDispatcher.accept(generatedPackPath, zipFile); - } catch (Exception e) { - this.plugin.logger().severe("Error merging resource pack", e); } - } catch (IOException e) { - throw new RuntimeException(e); + + this.generateFonts(generatedPackPath); + this.generateItemModels(generatedPackPath, this.plugin.itemManager()); + this.generateItemModels(generatedPackPath, this.plugin.blockManager()); + this.generateBlockOverrides(generatedPackPath); + this.generateLegacyItemOverrides(generatedPackPath); + this.generateModernItemOverrides(generatedPackPath); + this.generateModernItemModels1_21_2(generatedPackPath); + this.generateModernItemModels1_21_4(generatedPackPath); + this.generateOverrideSounds(generatedPackPath); + this.generateCustomSounds(generatedPackPath); + this.generateClientLang(generatedPackPath); + this.generateEquipments(generatedPackPath); + this.generateParticle(generatedPackPath); + Path zipFile = fs.getPath("resource_pack.zip"); + + try { + this.zipGenerator.accept(generatedPackPath, zipFile); + } catch (Exception e) { + this.plugin.logger().severe("Error zipping resource pack", e); + } + + Files.write(resourcePackPath(), Files.readAllBytes(zipFile)); + long end = System.currentTimeMillis(); + this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); + this.eventDispatcher.accept(generatedPackPath, resourcePackPath()); } } @@ -728,7 +730,6 @@ public abstract class AbstractPackManager implements PackManager { .resolve("assets") .resolve(entry.getKey()) .resolve("sounds.json"); - JsonObject soundJson; if (Files.exists(soundPath)) { try (BufferedReader reader = Files.newBufferedReader(soundPath)) { @@ -740,18 +741,15 @@ public abstract class AbstractPackManager implements PackManager { } else { soundJson = new JsonObject(); } - for (SoundEvent soundEvent : entry.getValue()) { soundJson.add(soundEvent.id().value(), soundEvent.get()); } - try { Files.createDirectories(soundPath.getParent()); } catch (IOException e) { plugin.logger().severe("Error creating " + soundPath.toAbsolutePath()); return; } - try (BufferedWriter writer = Files.newBufferedWriter(soundPath)) { GsonHelper.get().toJson(soundJson, writer); } catch (IOException e) { @@ -805,14 +803,12 @@ public abstract class AbstractPackManager implements PackManager { plugin.logger().warn("Cannot find " + originalKey.value() + " in sound template"); } } - try { Files.createDirectories(soundPath.getParent()); } catch (IOException e) { plugin.logger().severe("Error creating " + soundPath.toAbsolutePath()); return; } - try (BufferedWriter writer = Files.newBufferedWriter(soundPath)) { GsonHelper.get().toJson(soundJson, writer); } catch (IOException e) { @@ -1161,16 +1157,11 @@ public abstract class AbstractPackManager implements PackManager { providers.add(image.get()); } - try { - Files.writeString(fontPath, fontJson.toString().replace("\\\\u", "\\u")); + try (BufferedWriter writer = Files.newBufferedWriter(fontPath)) { + GsonHelper.get().toJson(fontJson, writer); } catch (IOException e) { - throw new RuntimeException(e); + this.plugin.logger().warn("Failed to save font for " + namespacedKey, e); } -// try (FileWriter fileWriter = new FileWriter(fontPath.toFile())) { -// fileWriter.write(fontJson.toString().replace("\\\\u", "\\u")); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } } if (Config.resourcePack$overrideUniform()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 44641827a..6e5391656 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import org.jetbrains.annotations.NotNull; +import java.io.IOException; import java.nio.file.Path; import java.util.Collection; @@ -32,7 +33,7 @@ public interface PackManager extends Manageable { } } - void generateResourcePack(); + void generateResourcePack() throws IOException; Path resourcePackPath(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 57ba00ab6..02c552472 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -310,7 +310,8 @@ public abstract class CraftEngine implements Plugin { Dependencies.AHO_CORASICK, Dependencies.LZ4, Dependencies.EVALEX, - Dependencies.JIMFS + Dependencies.JIMFS, + Dependencies.COMMONS_IMAGING ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java index 31e274fdc..2499f83d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java @@ -288,6 +288,14 @@ public class Dependencies { List.of(Relocation.of("jimfs", "com{}google{}common{}jimfs")) ); + public static final Dependency COMMONS_IMAGING = new Dependency( + "commons-imaging", + "org{}apache{}commons", + "commons-imaging", + "commons-imaging", + List.of(Relocation.of("imaging", "org{}apache{}commons{}imaging")) + ); + public static final Dependency AMAZON_AWSSDK_S3 = new Dependency( "amazon-sdk-s3", "software{}amazon{}awssdk", diff --git a/gradle.properties b/gradle.properties index 20e20af38..bbe6c86d5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,8 +39,9 @@ lz4_version=1.8.0 geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 +commons_imaging_version=1.0.0-alpha6 sparrow_nbt_version=0.7.3 -sparrow_util_version=0.42 +sparrow_util_version=0.45 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From bfc0741b08c63302c23b008c3801380a5633c7dd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 16 May 2025 21:11:27 +0800 Subject: [PATCH 69/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=BB=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/AbstractPackManager.java | 140 +++++++++++------- .../core/pack/CachedAssetFile.java | 25 ++++ .../core/pack/CachedConfigFile.java | 8 +- ...edConfig.java => CachedConfigSection.java} | 4 +- .../craftengine/core/pack/PackManager.java | 2 + .../craftengine/core/plugin/CraftEngine.java | 1 + 6 files changed, 121 insertions(+), 59 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/CachedAssetFile.java rename core/src/main/java/net/momirealms/craftengine/core/pack/{CachedConfig.java => CachedConfigSection.java} (81%) 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 ebcd6caa5..1c0e96027 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 @@ -19,7 +19,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; @@ -32,6 +31,7 @@ import net.momirealms.craftengine.core.sound.AbstractSoundManager; import net.momirealms.craftengine.core.sound.SoundEvent; import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; @@ -73,11 +73,11 @@ public abstract class AbstractPackManager implements PackManager { private final BiConsumer eventDispatcher; private final Map loadedPacks = new HashMap<>(); private final Map sectionParsers = new HashMap<>(); + private Map cachedConfigFiles = Collections.emptyMap(); + private Map cachedAssetFiles = Collections.emptyMap(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; - private Map cachedConfigFiles = Collections.emptyMap(); - public AbstractPackManager(CraftEngine plugin, BiConsumer eventDispatcher) { this.plugin = plugin; this.eventDispatcher = eventDispatcher; @@ -206,6 +206,15 @@ public abstract class AbstractPackManager implements PackManager { } } + @Override + public void initCachedAssets() { + try { + this.updateCachedAssets(null); + } catch (Exception e) { + this.plugin.logger().warn("Failed to update cached assets", e); + } + } + @NotNull @Override public Collection loadedPacks() { @@ -420,7 +429,8 @@ public abstract class AbstractPackManager implements PackManager { CachedConfigFile cachedFile = previousFiles.get(path); try { long lastModifiedTime = Files.getLastModifiedTime(path).toMillis(); - if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime) { + long size = Files.size(path); + if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime && cachedFile.size() == size) { this.cachedConfigFiles.put(path, cachedFile); continue; } @@ -428,7 +438,8 @@ public abstract class AbstractPackManager implements PackManager { Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); Map data = yaml.load(inputStream); if (data == null) continue; - this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime)); + + this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime, size)); } catch (Exception e) { this.plugin.logger().warn(path, "Error loading config file", e); } @@ -440,7 +451,7 @@ public abstract class AbstractPackManager implements PackManager { } private void loadResourceConfigs(Predicate predicate) { - TreeMap> cachedConfigs = new TreeMap<>(); + TreeMap> cachedConfigs = new TreeMap<>(); long o1 = System.nanoTime(); this.updateCachedConfigFiles(); for (Map.Entry fileEntry : this.cachedConfigFiles.entrySet()) { @@ -452,10 +463,10 @@ public abstract class AbstractPackManager implements PackManager { } long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); - for (Map.Entry> entry : cachedConfigs.entrySet()) { + for (Map.Entry> entry : cachedConfigs.entrySet()) { ConfigParser parser = entry.getKey(); long t1 = System.nanoTime(); - for (CachedConfig cached : entry.getValue()) { + for (CachedConfigSection cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); try { @@ -491,14 +502,14 @@ public abstract class AbstractPackManager implements PackManager { } } - private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { + private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); int hashIndex = key.indexOf('#'); String configType = hashIndex != -1 ? key.substring(0, hashIndex) : key; Optional.ofNullable(this.sectionParsers.get(configType)) .ifPresent(parser -> { - callback.accept(parser, new CachedConfig(key, castToMap(typeSections0, false), path, pack)); + callback.accept(parser, new CachedConfigSection(key, castToMap(typeSections0, false), path, pack)); }); } } @@ -533,22 +544,79 @@ public abstract class AbstractPackManager implements PackManager { // } // } - private void updateAssetsCache(List folders) { - + private List>> updateCachedAssets(@Nullable FileSystem fs) throws IOException { + List folders = new ArrayList<>(); + Map> conflictChecker = new HashMap<>(Math.max(128, this.cachedAssetFiles.size())); + Map previousFiles = this.cachedAssetFiles; + this.cachedAssetFiles = new HashMap<>(Math.max(128, this.cachedAssetFiles.size())); + folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); + folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); + for (Path sourceFolder : folders) { + if (Files.exists(sourceFolder)) { + Files.walkFileTree(sourceFolder, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + CachedAssetFile cachedAsset = previousFiles.get(file); + long lastModified = Files.getLastModifiedTime(file).toMillis(); + long size = Files.size(file); + if (cachedAsset != null && cachedAsset.lastModified() == lastModified && cachedAsset.size() == size) { + AbstractPackManager.this.cachedAssetFiles.put(file, cachedAsset); + } else { + cachedAsset = new CachedAssetFile(Files.readAllBytes(file), lastModified, size); + AbstractPackManager.this.cachedAssetFiles.put(file, cachedAsset); + } + if (fs == null) return FileVisitResult.CONTINUE; + Path relative = sourceFolder.relativize(file); + Path targetPath = fs.getPath("resource_pack/" + relative.toString().replace("\\", "/")); + List conflicts = conflictChecker.get(relative); + if (conflicts == null) { + Files.createDirectories(targetPath.getParent()); + Files.write(targetPath, cachedAsset.data()); + conflictChecker.put(relative, List.of(file)); + } else { + PathContext relativeCTX = PathContext.of(relative); + PathContext targetCTX = PathContext.of(targetPath); + PathContext fileCTX = PathContext.of(file); + for (ResolutionConditional resolution : Config.resolutions()) { + if (resolution.matcher().test(relativeCTX)) { + resolution.resolution().run(targetCTX, fileCTX); + return FileVisitResult.CONTINUE; + } + } + switch (conflicts.size()) { + case 1 -> conflictChecker.put(relative, List.of(conflicts.get(0), file)); + case 2 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), file)); + case 3 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), file)); + case 4 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), conflicts.get(3), file)); + default -> { + // just ignore it if it has many conflict files + } + } + } + return FileVisitResult.CONTINUE; + } + }); + } + } + List>> conflicts = new ArrayList<>(); + for (Map.Entry> entry : conflictChecker.entrySet()) { + if (entry.getValue().size() > 1) { + conflicts.add(Pair.of(entry.getKey(), entry.getValue())); + } + } + return conflicts; } @Override public void generateResourcePack() throws IOException { this.plugin.logger().info("Generating resource pack..."); long start = System.currentTimeMillis(); + // get the target location try (FileSystem fs = Jimfs.newFileSystem(Configuration.forCurrentPlatform())) { // firstly merge existing folders Path generatedPackPath = fs.getPath("resource_pack"); - List folders = new ArrayList<>(); - folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); - folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); - List>> duplicated = mergeFolder(folders, fs); + List>> duplicated = this.updateCachedAssets(fs); if (!duplicated.isEmpty()) { plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); int x = 1; @@ -1182,44 +1250,4 @@ public abstract class AbstractPackManager implements PackManager { } } } - - private List>> mergeFolder(Collection sourceFolders, FileSystem fs) throws IOException { - Map> conflictChecker = new HashMap<>(); - for (Path sourceFolder : sourceFolders) { - if (Files.exists(sourceFolder)) { - Files.walkFileTree(sourceFolder, new SimpleFileVisitor<>() { - @Override - public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { - Path relative = sourceFolder.relativize(file); - Path targetPath = fs.getPath("resource_pack/" + relative.toString().replace("\\", "/")); - List conflicts = conflictChecker.computeIfAbsent(relative, k -> new ArrayList<>()); - if (conflicts.isEmpty()) { - Files.createDirectories(targetPath.getParent()); - Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING); - conflicts.add(file); - } else { - PathContext relativeCTX = PathContext.of(relative); - PathContext targetCTX = PathContext.of(targetPath); - PathContext fileCTX = PathContext.of(file); - for (ResolutionConditional resolution : Config.resolutions()) { - if (resolution.matcher().test(relativeCTX)) { - resolution.resolution().run(targetCTX, fileCTX); - return FileVisitResult.CONTINUE; - } - } - conflicts.add(file); - } - return FileVisitResult.CONTINUE; - } - }); - } - } - List>> conflicts = new ArrayList<>(); - for (Map.Entry> entry : conflictChecker.entrySet()) { - if (entry.getValue().size() > 1) { - conflicts.add(Pair.of(entry.getKey(), entry.getValue())); - } - } - return conflicts; - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedAssetFile.java b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedAssetFile.java new file mode 100644 index 000000000..f86687e40 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedAssetFile.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.pack; + +public class CachedAssetFile { + private final byte[] data; + private final long lastModified; + private final long size; + + public CachedAssetFile(byte[] data, long lastModified, long size) { + this.data = data; + this.lastModified = lastModified; + this.size = size; + } + + public byte[] data() { + return data; + } + + public long lastModified() { + return lastModified; + } + + public long size() { + return size; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java index c39cf4e36..f4cb38fd5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java @@ -5,10 +5,12 @@ import java.util.Map; public class CachedConfigFile { private final Map config; private final long lastModified; + private final long size; private final Pack pack; - public CachedConfigFile(Map config, Pack pack, long lastModified) { + public CachedConfigFile(Map config, Pack pack, long lastModified, long size) { this.config = config; + this.size = size; this.lastModified = lastModified; this.pack = pack; } @@ -24,4 +26,8 @@ public class CachedConfigFile { public long lastModified() { return lastModified; } + + public long size() { + return size; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfig.java b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigSection.java similarity index 81% rename from core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfig.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigSection.java index e98faf8f8..e8016ce2a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfig.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigSection.java @@ -3,13 +3,13 @@ package net.momirealms.craftengine.core.pack; import java.nio.file.Path; import java.util.Map; -public class CachedConfig { +public class CachedConfigSection { private final Pack pack; private final Path filePath; private final String prefix; private final Map config; - public CachedConfig(String prefix, Map config, Path filePath, Pack pack) { + public CachedConfigSection(String prefix, Map config, Path filePath, Pack pack) { this.config = config; this.filePath = filePath; this.pack = pack; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 6e5391656..839de5886 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -14,6 +14,8 @@ public interface PackManager extends Manageable { void loadResources(boolean recipe); + void initCachedAssets(); + @NotNull Collection loadedPacks(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 02c552472..53f8b5da5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -234,6 +234,7 @@ public abstract class CraftEngine implements Plugin { // set up some platform extra tasks this.platformDelayedEnable(); this.isInitializing = false; + this.scheduler.executeAsync(() -> this.packManager.initCachedAssets()); }); } From a870532f7e1d0dea758ac953e1b8a91831a24f64 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 16 May 2025 21:23:21 +0800 Subject: [PATCH 70/73] =?UTF-8?q?=E4=BF=AE=E5=A5=BD=E4=BA=86=E5=96=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/pack/AbstractPackManager.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 1c0e96027..c473e100f 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 @@ -1188,7 +1188,7 @@ public abstract class AbstractPackManager implements PackManager { private void generateFonts(Path generatedPackPath) { // generate image font json - for (Font font : plugin.fontManager().fonts()) { + for (Font font : this.plugin.fontManager().fonts()) { Key namespacedKey = font.key(); Path fontPath = generatedPackPath.resolve("assets") .resolve(namespacedKey.namespace()) @@ -1202,14 +1202,14 @@ public abstract class AbstractPackManager implements PackManager { fontJson = JsonParser.parseString(content).getAsJsonObject(); } catch (IOException e) { fontJson = new JsonObject(); - plugin.logger().warn(fontPath + " is not a valid font json file"); + this.plugin.logger().warn(fontPath + " is not a valid font json file"); } } else { fontJson = new JsonObject(); try { Files.createDirectories(fontPath.getParent()); } catch (IOException e) { - throw new RuntimeException(e); + this.plugin.logger().severe("Error creating " + fontPath.toAbsolutePath(), e); } } @@ -1225,10 +1225,10 @@ public abstract class AbstractPackManager implements PackManager { providers.add(image.get()); } - try (BufferedWriter writer = Files.newBufferedWriter(fontPath)) { - GsonHelper.get().toJson(fontJson, writer); + try { + Files.writeString(fontPath, fontJson.toString().replace("\\\\u", "\\u")); } catch (IOException e) { - this.plugin.logger().warn("Failed to save font for " + namespacedKey, e); + this.plugin.logger().severe("Error writing font to " + fontPath.toAbsolutePath(), e); } } From 49cddbed23c1cf7c8e91f46ea56bf1ca96700ae4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 17 May 2025 01:19:04 +0800 Subject: [PATCH 71/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D1.20.6=20itemstack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 2 ++ .../craftengine/bukkit/item/ComponentItemWrapper.java | 4 ++-- .../craftengine/core/pack/AbstractPackManager.java | 7 ++++--- .../momirealms/craftengine/core/plugin/config/Config.java | 2 ++ gradle.properties | 6 +++--- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 297be7fe4..e42bbb4be 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -65,6 +65,8 @@ resource-pack: - CustomNameplates/ResourcePack - BetterModel/build - BetterHud/build + merge-external-zip-files: + - CraftEngine/external_packs/example.zip delivery: # Send the resource pack on joining the server send-on-join: true 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 7a6e7c0a3..b7c1eb500 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 @@ -14,11 +14,11 @@ public class ComponentItemWrapper implements ItemWrapper { private final ItemStack item; public ComponentItemWrapper(final ItemStack item) { - this.item = item; + this.item = FastNMS.INSTANCE.ensureCraftItemStack(item); } public ComponentItemWrapper(final ItemStack item, int count) { - this.item = item; + this.item = FastNMS.INSTANCE.ensureCraftItemStack(item); this.item.setAmount(count); } 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 c473e100f..c21899ae4 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 @@ -646,17 +646,18 @@ public abstract class AbstractPackManager implements PackManager { this.generateEquipments(generatedPackPath); this.generateParticle(generatedPackPath); Path zipFile = fs.getPath("resource_pack.zip"); - + Path finalPath = resourcePackPath(); try { this.zipGenerator.accept(generatedPackPath, zipFile); } catch (Exception e) { this.plugin.logger().severe("Error zipping resource pack", e); } - Files.write(resourcePackPath(), Files.readAllBytes(zipFile)); + Files.createDirectories(finalPath.getParent()); + Files.write(finalPath, Files.readAllBytes(zipFile)); long end = System.currentTimeMillis(); this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); - this.eventDispatcher.accept(generatedPackPath, resourcePackPath()); + this.eventDispatcher.accept(generatedPackPath, finalPath); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index fde4746d5..d6faf0675 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -58,6 +58,7 @@ public class Config { protected boolean resource_pack$override_uniform_font; protected List resource_pack$duplicated_files_handler; protected List resource_pack$merge_external_folders; + protected List resource_pack$merge_external_zips; protected boolean resource_pack$protection$crash_tools$method_1; protected boolean resource_pack$protection$crash_tools$method_2; @@ -218,6 +219,7 @@ public class Config { resource_pack$supported_version$min = getVersion(config.get("resource-pack.supported-version.min", "1.20").toString()); resource_pack$supported_version$max = getVersion(config.get("resource-pack.supported-version.max", "LATEST").toString()); resource_pack$merge_external_folders = config.getStringList("resource-pack.merge-external-folders"); + resource_pack$merge_external_zips = config.getStringList("resource-pack.merge-external-zip-files"); resource_pack$delivery$send_on_join = config.getBoolean("resource-pack.delivery.send-on-join", true); resource_pack$delivery$resend_on_upload = config.getBoolean("resource-pack.delivery.resend-on-upload", true); resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true); diff --git a/gradle.properties b/gradle.properties index bbe6c86d5..f91502ba9 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.53.9 +project_version=0.0.53.10 config_version=32 lang_version=12 project_group=net.momirealms @@ -41,7 +41,7 @@ zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 sparrow_nbt_version=0.7.3 -sparrow_util_version=0.45 +sparrow_util_version=0.46 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 @@ -51,7 +51,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.15 -nms_helper_version=0.65.23 +nms_helper_version=0.65.24 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 81595ba36430f6437b3312b8334066dc2266f4d7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 17 May 2025 02:27:09 +0800 Subject: [PATCH 72/73] 0.0.54 --- .../craftengine/core/pack/AbstractPackManager.java | 7 ++----- gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) 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 c21899ae4..caf68d43b 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 @@ -645,16 +645,13 @@ public abstract class AbstractPackManager implements PackManager { this.generateClientLang(generatedPackPath); this.generateEquipments(generatedPackPath); this.generateParticle(generatedPackPath); - Path zipFile = fs.getPath("resource_pack.zip"); Path finalPath = resourcePackPath(); + Files.createDirectories(finalPath.getParent()); try { - this.zipGenerator.accept(generatedPackPath, zipFile); + this.zipGenerator.accept(generatedPackPath, finalPath); } catch (Exception e) { this.plugin.logger().severe("Error zipping resource pack", e); } - - Files.createDirectories(finalPath.getParent()); - Files.write(finalPath, Files.readAllBytes(zipFile)); long end = System.currentTimeMillis(); this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); this.eventDispatcher.accept(generatedPackPath, finalPath); diff --git a/gradle.properties b/gradle.properties index f91502ba9..07446d33e 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.53.10 +project_version=0.0.54 config_version=32 lang_version=12 project_group=net.momirealms @@ -41,7 +41,7 @@ zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 sparrow_nbt_version=0.7.3 -sparrow_util_version=0.46 +sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From abbab87a017b3e9e47c2adba3cb9c9bf8a2ce8c0 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 17 May 2025 02:27:18 +0800 Subject: [PATCH 73/73] Update gradle.properties --- gradle.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index 07446d33e..d97675755 100644 --- a/gradle.properties +++ b/gradle.properties @@ -71,9 +71,9 @@ modmenu_version=13.0.3 cloth_version=17.0.144 # Proxy settings -systemProp.socks.proxyHost=127.0.0.1 -systemProp.socks.proxyPort=7890 -systemProp.http.proxyHost=127.0.0.1 -systemProp.http.proxyPort=7890 -systemProp.https.proxyHost=127.0.0.1 -systemProp.https.proxyPort=7890 \ No newline at end of file +#systemProp.socks.proxyHost=127.0.0.1 +#systemProp.socks.proxyPort=7890 +#systemProp.http.proxyHost=127.0.0.1 +#systemProp.http.proxyPort=7890 +#systemProp.https.proxyHost=127.0.0.1 +#systemProp.https.proxyPort=7890 \ No newline at end of file