From 3c3c5c00dd2fcad87858cf24c5a2643acf1fc197 Mon Sep 17 00:00:00 2001 From: iqtester Date: Wed, 16 Jul 2025 22:13:17 -0400 Subject: [PATCH 01/21] prevent multi-layer snow replacement --- .../craftengine/bukkit/world/BukkitBlockInWorld.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 170c50dd1..8d0451af7 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 @@ -10,7 +10,9 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.data.type.Snow; public class BukkitBlockInWorld implements BlockInWorld { private final Block block; @@ -25,6 +27,10 @@ public class BukkitBlockInWorld implements BlockInWorld { if (customState != null && !customState.isEmpty()) { return customState.behavior().canBeReplaced(context, customState); } + if (this.block.getType() == Material.SNOW) { + Snow snow = (Snow) block.getBlockData(); + return snow.getLayers() == 1; + } return this.block.isReplaceable(); } From fd94643440d752624969384f6ac26c3e470224dc Mon Sep 17 00:00:00 2001 From: iqtester Date: Thu, 17 Jul 2025 14:34:05 -0400 Subject: [PATCH 02/21] retrieving vanilla state once --- .../bukkit/world/BukkitBlockInWorld.java | 15 ++++++++++----- .../craftengine/core/item/ItemKeys.java | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) 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 8d0451af7..a0596469f 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 @@ -3,14 +3,15 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.type.Snow; @@ -23,15 +24,19 @@ public class BukkitBlockInWorld implements BlockInWorld { @Override public boolean canBeReplaced(BlockPlaceContext context) { - ImmutableBlockState customState = CraftEngineBlocks.getCustomBlockState(this.block); + Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.block.getWorld()); + Object blockPos = LocationUtils.toBlockPos(this.block.getX(), this.block.getY(), this.block.getZ()); + Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos); + + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (customState != null && !customState.isEmpty()) { return customState.behavior().canBeReplaced(context, customState); } - if (this.block.getType() == Material.SNOW) { - Snow snow = (Snow) block.getBlockData(); + if (BlockStateUtils.getBlockOwnerIdFromState(state).equals(ItemKeys.SNOW)) { + Snow snow = (Snow) BlockStateUtils.fromBlockData(state); return snow.getLayers() == 1; } - return this.block.isReplaceable(); + return BlockStateUtils.isReplaceable(state); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 89916d9e3..a1991a9f8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -33,6 +33,7 @@ public class ItemKeys { public static final Key BARRIER = Key.of("minecraft:barrier"); public static final Key CACTUS = Key.of("minecraft:cactus"); public static final Key REDSTONE = Key.of("minecraft:redstone"); + public static final Key SNOW = Key.of("minecraft:snow"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From 84725e177ee77e358fcbee0193567324fbfe1ad9 Mon Sep 17 00:00:00 2001 From: iqtester Date: Thu, 17 Jul 2025 16:32:23 -0400 Subject: [PATCH 03/21] improve comparison --- .../bukkit/plugin/reflection/minecraft/MBlocks.java | 2 ++ .../craftengine/bukkit/world/BukkitBlockInWorld.java | 4 ++-- .../java/net/momirealms/craftengine/core/item/ItemKeys.java | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java index 2cf9d1613..34d2f0e65 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java @@ -17,6 +17,7 @@ public final class MBlocks { public static final Object SHORT_GRASS$defaultState; public static final Object SHULKER_BOX; public static final Object COMPOSTER; + public static final Object SNOW; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -35,5 +36,6 @@ public final class MBlocks { SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); SHULKER_BOX = getById("shulker_box"); COMPOSTER = getById("composter"); + SNOW = getById("snow"); } } 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 a0596469f..6b6b6e675 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 @@ -2,12 +2,12 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.World; @@ -32,7 +32,7 @@ public class BukkitBlockInWorld implements BlockInWorld { if (customState != null && !customState.isEmpty()) { return customState.behavior().canBeReplaced(context, customState); } - if (BlockStateUtils.getBlockOwnerIdFromState(state).equals(ItemKeys.SNOW)) { + if (BlockStateUtils.getBlockOwner(state) == MBlocks.SNOW) { Snow snow = (Snow) BlockStateUtils.fromBlockData(state); return snow.getLayers() == 1; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index a1991a9f8..89916d9e3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -33,7 +33,6 @@ public class ItemKeys { public static final Key BARRIER = Key.of("minecraft:barrier"); public static final Key CACTUS = Key.of("minecraft:cactus"); public static final Key REDSTONE = Key.of("minecraft:redstone"); - public static final Key SNOW = Key.of("minecraft:snow"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE From 4c47407ba356e3ff83feee06602cb06704dabab9 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 18 Jul 2025 17:00:55 +0800 Subject: [PATCH 04/21] =?UTF-8?q?refactor(bukkit):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=9B=AA=E7=9A=84=E6=9B=BF=E6=8D=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reflection/minecraft/CoreReflections.java | 23 +++++++++++++++++++ .../bukkit/util/BlockStateUtils.java | 7 ++++++ .../bukkit/world/BukkitBlockInWorld.java | 10 +++----- gradle.properties | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index b8e41241c..77076e777 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3873,4 +3873,27 @@ public final class CoreReflections { throw new ReflectionInitException("Failed to initialize HashOps", e); } } + + public static final Class clazz$SnowLayerBlock = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.block.BlockSnow", + "world.level.block.SnowLayerBlock" + ) + ); + + public static final Field field$SnowLayerBlock$LAYERS = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$SnowLayerBlock, clazz$IntegerProperty, 0 + ) + ); + + public static final Object instance$SnowLayerBlock$LAYERS; + + static { + try { + instance$SnowLayerBlock$LAYERS = field$SnowLayerBlock$LAYERS.get(null); + } catch (IllegalAccessException e) { + throw new ReflectionInitException("Failed to initialize SnowLayerBlock$LAYERS", e); + } + } } 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 e575d2f20..00c8dfc57 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 @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.DelegatingBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; +import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -142,4 +143,10 @@ public class BlockStateUtils { Object blockOwner = getBlockOwner(state); return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0; } + + public static Object getBlockState(Block block) { + Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()); + Object blockPos = LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ()); + return FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos); + } } 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 6b6b6e675..6a9ce89a4 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 @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -13,7 +14,6 @@ import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; import org.bukkit.block.Block; -import org.bukkit.block.data.type.Snow; public class BukkitBlockInWorld implements BlockInWorld { private final Block block; @@ -24,17 +24,13 @@ public class BukkitBlockInWorld implements BlockInWorld { @Override public boolean canBeReplaced(BlockPlaceContext context) { - Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.block.getWorld()); - Object blockPos = LocationUtils.toBlockPos(this.block.getX(), this.block.getY(), this.block.getZ()); - Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos); - + Object state = BlockStateUtils.getBlockState(this.block); ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (customState != null && !customState.isEmpty()) { return customState.behavior().canBeReplaced(context, customState); } if (BlockStateUtils.getBlockOwner(state) == MBlocks.SNOW) { - Snow snow = (Snow) BlockStateUtils.fromBlockData(state); - return snow.getLayers() == 1; + return (int) FastNMS.INSTANCE.method$StateHolder$getValue(state, CoreReflections.instance$SnowLayerBlock$LAYERS) == 1; } return BlockStateUtils.isReplaceable(state); } diff --git a/gradle.properties b/gradle.properties index 649a773b0..ef51839f9 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.18 -nms_helper_version=1.0.36 +nms_helper_version=1.0.37 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From f5d9bd8c1a1d0794a8ec8d7332ebb759470297e4 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 18 Jul 2025 19:12:05 +0800 Subject: [PATCH 05/21] =?UTF-8?q?refactor(network):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=BD=91=E7=BB=9C=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 10 +-- .../network/payload/NetWorkDataTypes.java | 66 +++++-------------- 2 files changed, 20 insertions(+), 56 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 21685624a..8233043b3 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 @@ -1891,9 +1891,9 @@ public class PacketConsumers { if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; FriendlyByteBuf buf = discardedPayload.toBuffer(); - NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); + NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); + int clientBlockRegistrySize = dataType.decode(buf); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); if (clientBlockRegistrySize != serverBlockRegistrySize) { user.kick(Component.translatable( @@ -1906,10 +1906,10 @@ public class PacketConsumers { user.setClientModState(true); } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { if (!VersionHelper.isOrAbove1_20_2()) return; - if (dataType.as(Boolean.class).decode(buf)) { + if (dataType.decode(buf)) { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - dataType.writeType(bufPayload); - dataType.as(Boolean.class).encode(bufPayload, true); + bufPayload.writeEnumConstant(dataType); + dataType.encode(bufPayload, true); user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java index 5655e1028..37da1618d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java @@ -1,64 +1,28 @@ package net.momirealms.craftengine.bukkit.plugin.network.payload; +import io.netty.buffer.ByteBuf; -import net.momirealms.craftengine.core.util.FriendlyByteBuf; +public enum NetWorkDataTypes { + CLIENT_CUSTOM_BLOCK(NetWorkCodecs.INTEGER), + CANCEL_BLOCK_UPDATE(NetWorkCodecs.BOOLEAN); -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Function; + private final NetWorkCodec codec; -public class NetWorkDataTypes { - private static final Map> id2NetWorkDataTypes = new HashMap<>(); - - public static final NetWorkDataTypes CLIENT_CUSTOM_BLOCK = - new NetWorkDataTypes<>(0, FriendlyByteBuf::readInt, FriendlyByteBuf::writeInt); - - public static final NetWorkDataTypes CANCEL_BLOCK_UPDATE = - new NetWorkDataTypes<>(1, FriendlyByteBuf::readBoolean, FriendlyByteBuf::writeBoolean); - - static { - register(CLIENT_CUSTOM_BLOCK); - register(CANCEL_BLOCK_UPDATE); + NetWorkDataTypes(NetWorkCodec codec) { + this.codec = codec; } - private static void register(NetWorkDataTypes type) { - id2NetWorkDataTypes.put(type.id, type); + public NetWorkCodec codec() { + return codec; } - 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 = encoder; + @SuppressWarnings("unchecked") + public V decode(ByteBuf buf) { + return (V) codec.decode(buf); } - public T decode(FriendlyByteBuf buf) { - return decoder.apply(buf); - } - - 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", "unused"}) - public NetWorkDataTypes as(Class clazz) { - return (NetWorkDataTypes) this; + @SuppressWarnings("unchecked") + public void encode(ByteBuf buf, V value) { + ((NetWorkCodec) codec).encode(buf, value); } } \ No newline at end of file From 453c1f5c1f5c79db2bbacec58350dd99fbb8dcae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 00:28:55 +0800 Subject: [PATCH 06/21] feat: split lore components --- .../factory/ComponentItemFactory1_21_5.java | 6 +---- .../craftengine/core/item/ItemFactory.java | 3 +-- .../core/util/AdventureHelper.java | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index af0981b60..af576f13d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -90,11 +90,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { - List loreTags = new ArrayList<>(); - for (Component component : lore) { - loreTags.add(AdventureHelper.componentToTag(component)); - } - item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(lore.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToTag).toList())); } } 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 d403ba310..996db1af9 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 @@ -16,7 +16,6 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; @@ -112,7 +111,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); + loreJson(item, component.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToJson).toList()); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 3ed1f6048..92d81f1da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -1,11 +1,17 @@ package net.momirealms.craftengine.core.util; import com.google.gson.JsonElement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -29,6 +35,7 @@ public class AdventureHelper { private final MiniMessage miniMessageCustom; private final GsonComponentSerializer gsonComponentSerializer; private final NBTComponentSerializer nbtComponentSerializer; + private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build(); private AdventureHelper() { this.miniMessage = MiniMessage.builder().build(); @@ -209,6 +216,24 @@ public class AdventureHelper { return getNBT().deserialize(tag); } + public static List split(Component component) { + List result = new ArrayList<>(1); + Component line = Component.empty(); + for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { + Component child = it.next().children(Collections.emptyList()); + if (Component.EQUALS.test(child, Component.newline())) { + result.add(line); + line = Component.empty(); + } else { + line = line.append(child); + } + } + if (Component.IS_NOT_EMPTY.test(line)) { + result.add(line); + } + return result; + } + /** * Checks if a character is a legacy color code. * From 0c6624819c476440e57d5a30429e65cee9bcbe80 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 10:59:33 +0800 Subject: [PATCH 07/21] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=90=AF=E7=94=A8=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A8=A1=E7=BB=84?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 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 21685624a..49caecbe3 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 @@ -105,7 +105,7 @@ public class PacketConsumers { byte yHeadRot = buf.readByte(); int data = buf.readVarInt(); // Falling blocks - int remapped = remap(data); + int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data); if (remapped != data) { int xa = buf.readShort(); int ya = buf.readShort(); @@ -428,7 +428,7 @@ public class PacketConsumers { if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { return; } - int state = remap(before); + int state = user.clientModEnabled() ? remapMOD(before) : remap(before); if (state == before) { return; } @@ -450,7 +450,7 @@ public class PacketConsumers { BlockPos blockPos = buf.readBlockPos(); int state = buf.readInt(); boolean global = buf.readBoolean(); - int newState = remap(state); + int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); if (newState == state) { return; } @@ -1006,7 +1006,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1046,7 +1046,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); @@ -1086,7 +1086,7 @@ public class PacketConsumers { if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); int id = BlockStateUtils.blockStateToId(blockState); - int remapped = remap(id); + int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); if (remapped == id) return; Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); From 17b531c56ca3b26bd22ce8823a25c91360ad7ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 22:32:37 +0800 Subject: [PATCH 08/21] feat: better split lore impl --- .../factory/ComponentItemFactory1_21_5.java | 6 ++- .../core/item/AbstractItemManager.java | 23 +++++++--- .../craftengine/core/item/ItemFactory.java | 3 +- .../item/modifier/DynamicLoreModifier.java | 13 +++--- .../core/item/modifier/LoreModification.java | 45 +++++++++++++++++++ .../core/item/modifier/LoreModifier.java | 28 ++++-------- .../core/util/AdventureHelper.java | 2 +- .../core/util/ResourceConfigUtils.java | 11 +++++ 8 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index af576f13d..af0981b60 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -90,7 +90,11 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { - item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(lore.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToTag).toList())); + List loreTags = new ArrayList<>(); + for (Component component : lore) { + loreTags.add(AdventureHelper.componentToTag(component)); + } + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 6b75dc648..5aebb5f74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -534,15 +534,26 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new CustomNameModifier<>(name); }, "custom-name", "item-name", "display-name"); } + Function> loreModificationListParser = (obj) -> { + if (obj instanceof List list) { + List modifications = new ArrayList<>(list.size()); + for (Object entry : list) { + if (entry instanceof Map map) { + modifications.add(new LoreModification(ResourceConfigUtils.getAsEnumOrDefault(map.get("action").toString().toUpperCase(Locale.ROOT), LoreModification.Action.class, LoreModification.Action.SET), ResourceConfigUtils.getAsInt(map.get("priority"), "priority"), ResourceConfigUtils.getAsBoolean(map.get("split-lines"), "split-lines"), MiscUtils.getAsStringList(map.get("content")))); + } else { + modifications.add(new LoreModification(List.of(entry.toString()))); + } + } + return modifications; + } + return Collections.emptyList(); + }; + registerDataType((obj) -> new LoreModifier<>(loreModificationListParser.apply(obj)), "lore", "display-lore", "description"); registerDataType((obj) -> { - List lore = MiscUtils.getAsStringList(obj); - return new LoreModifier<>(lore); - }, "lore", "display-lore", "description"); - registerDataType((obj) -> { - Map> dynamicLore = new LinkedHashMap<>(); + Map> dynamicLore = new LinkedHashMap<>(); if (obj instanceof Map map) { for (Map.Entry entry : map.entrySet()) { - dynamicLore.put(entry.getKey().toString(), MiscUtils.getAsStringList(entry.getValue())); + dynamicLore.put(entry.getKey().toString(), loreModificationListParser.apply(entry.getValue())); } } return new DynamicLoreModifier<>(dynamicLore); 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 996db1af9..bed14fa59 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; +import java.util.stream.Collectors; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -111,7 +112,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::split).flatMap(List::stream).map(AdventureHelper::componentToJson).toList()); + loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java index 65392a1b8..fd7bd99d3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java @@ -1,10 +1,11 @@ package net.momirealms.craftengine.core.item.modifier; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -16,15 +17,15 @@ import java.util.Optional; public class DynamicLoreModifier implements ItemDataModifier { public static final String CONTEXT_TAG_KEY = "craftengine:display_context"; - private final Map> displayContexts; + private final Map> displayContexts; private final String defaultContext; - public DynamicLoreModifier(Map> displayContexts) { + public DynamicLoreModifier(Map> displayContexts) { this.defaultContext = displayContexts.keySet().iterator().next(); this.displayContexts = displayContexts; } - public Map> displayContexts() { + public Map> displayContexts() { return Collections.unmodifiableMap(this.displayContexts); } @@ -36,11 +37,11 @@ public class DynamicLoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultContext).toString(); - List lore = this.displayContexts.get(displayContext); + List lore = this.displayContexts.get(displayContext); if (lore == null) { lore = this.displayContexts.get(this.defaultContext); } - item.loreComponent(lore.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + item.loreComponent(lore.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java new file mode 100644 index 000000000..45ecd76ae --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.item.modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +public record LoreModification(Action action, int priority, boolean split, List content) implements Comparable { + public LoreModification(List content) { + this(Action.SET, 0, false, content); + } + public LoreModification(Action action, int priority, boolean split, List content) { + this.action = action; + this.priority = priority; + this.split = split; + if (Config.addNonItalicTag()) { + List processed = new ArrayList<>(content.size()); + for (String arg : content) { + processed.add(arg.startsWith("") ? arg : "" + arg); + } + this.content = processed; + } else { + this.content = content; + } + } + public Stream apply(Stream lore, ItemBuildContext context) { + return switch (action) { + case PREPEND -> Stream.concat(parseContent(context), lore); + case APPEND -> Stream.concat(lore, parseContent(context)); + default -> parseContent(context); + }; + } + private Stream parseContent(ItemBuildContext context) { + Stream parsed = content.stream().map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); + return split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; + } + @Override + public int compareTo(LoreModification other) { + return Integer.compare(priority, other.priority); + } + public enum Action { + SET, PREPEND, APPEND + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java index 6c5c88a59..f76c1bb60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java @@ -1,35 +1,25 @@ package net.momirealms.craftengine.core.item.modifier; +import java.util.ArrayList; +import java.util.stream.Stream; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; -import java.util.ArrayList; import java.util.List; public class LoreModifier implements ItemDataModifier { - private final List argument; + private final List argument; - public LoreModifier(List argument) { - if (Config.addNonItalicTag()) { - List processed = new ArrayList<>(argument.size()); - for (String arg : argument) { - if (arg.startsWith("")) { - processed.add(arg); - } else { - processed.add("" + arg); - } - } - this.argument = processed; - } else { - this.argument = argument; - } + public LoreModifier(List argument) { + argument = new ArrayList<>(argument); + argument.sort(null); + this.argument = List.copyOf(argument); } @Override @@ -39,7 +29,7 @@ public class LoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + item.loreComponent(argument.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 92d81f1da..f58769a92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -216,7 +216,7 @@ public class AdventureHelper { return getNBT().deserialize(tag); } - public static List split(Component component) { + public static List splitLines(Component component) { List result = new ArrayList<>(1); Component line = Component.empty(); for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index b6a40aa27..a9671f7de 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -20,6 +20,17 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } + public static > E getAsEnumOrDefault(Object o, Class clazz, E defaultValue) { + if (o == null) { + return defaultValue; + } + try { + return Enum.valueOf(clazz, o.toString()); + } catch (IllegalArgumentException e) { + return defaultValue; + } + } + public static T requireNonNullOrThrow(T obj, String node) { if (obj == null) throw new LocalizedResourceConfigException(node); From f68432b761487eb9ae923d2286d8eec130a18a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sat, 19 Jul 2025 22:44:12 +0800 Subject: [PATCH 09/21] refractor: import --- .../java/net/momirealms/craftengine/core/item/ItemFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bed14fa59..d403ba310 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 @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; -import java.util.stream.Collectors; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.FireworkExplosion; @@ -17,6 +16,7 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; From af7241aade85ed56c627e96c8fef82a9687e11e8 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 22:54:48 +0800 Subject: [PATCH 10/21] =?UTF-8?q?fix(network):=20=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D1.20.2~1.20.4=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E6=A8=A1=E7=BB=84=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 41 +------------------ .../plugin/network/PacketConsumers.java | 3 +- 2 files changed, 3 insertions(+), 41 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 a8d5c862d..161171c20 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,23 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.entity.data.HappyGhastData; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.incendo.cloud.Command; -import org.incendo.cloud.bukkit.parser.location.LocationParser; -import org.incendo.cloud.parser.standard.IntegerParser; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; public class TestCommand extends BukkitCommandFeature { @@ -29,35 +18,9 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("location", LocationParser.locationParser()) - .required("remove", IntegerParser.integerParser()) .handler(context -> { Player player = context.sender(); - int removeEntityId = context.get("remove"); - if (removeEntityId >= 0) { - try { - Object packet = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{removeEntityId}); - plugin().adapt(player).sendPacket(packet, true); - player.sendMessage("发送成功"); - } catch (ReflectiveOperationException e) { - player.sendMessage("发送失败"); - } - return; - } - Location location = context.get("location"); - int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); - List packets = new ArrayList<>(); - List cachedShulkerValues = new ArrayList<>(); - HappyGhastData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, cachedShulkerValues); // NO AI - // HappyGhastData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, cachedShulkerValues); // Invisible - HappyGhastData.StaysStill.addEntityDataIfNotDefaultValue(true, cachedShulkerValues); - packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - entityId, UUID.randomUUID(), location.x(), location.y(), location.z(), 0, location.getYaw(), - MEntityTypes.HAPPY_GHAST, 0, CoreReflections.instance$Vec3$Zero, 0 - )); - packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, List.copyOf(cachedShulkerValues))); - plugin().adapt(player).sendPackets(packets, true); - player.sendMessage("发送成功 id: " + entityId); + player.sendMessage("客户端模组状态: " + BukkitNetworkManager.instance().getUser(player).clientModEnabled()); }); } 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 49caecbe3..72a2571c7 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 @@ -1884,7 +1884,7 @@ public class PacketConsumers { public static final TriConsumer CUSTOM_PAYLOAD = (user, event, packet) -> { try { - if (!VersionHelper.isOrAbove1_20_5()) return; + if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { Payload discardedPayload = DiscardedPayload.from(payload); @@ -1905,7 +1905,6 @@ public class PacketConsumers { } user.setClientModState(true); } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (!VersionHelper.isOrAbove1_20_2()) return; if (dataType.as(Boolean.class).decode(buf)) { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); dataType.writeType(bufPayload); From 407d0137252fbedc76c80c9315e8ee188810f413 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:21:19 +0800 Subject: [PATCH 11/21] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D1.20.2~?= =?UTF-8?q?1.20.4=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=A8=A1=E7=BB=84=E6=A3=80?= =?UTF-8?q?=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 53 +++++++++++-------- .../network/payload/UnknownPayload.java | 28 ++++++++++ .../minecraft/NetworkReflections.java | 18 +++++++ 3 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java 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 72a2571c7..661920946 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 @@ -29,6 +29,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; @@ -1886,31 +1887,37 @@ public class PacketConsumers { try { if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + System.out.println(payload.getClass()); + Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { - Payload discardedPayload = DiscardedPayload.from(payload); - if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + clientPayload = DiscardedPayload.from(payload); + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$UnknownPayload.isInstance(payload)) { + clientPayload = UnknownPayload.from(payload); + } else { + return; + } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + return; + FriendlyByteBuf buf = clientPayload.toBuffer(); + NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); + if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { + int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (clientBlockRegistrySize != serverBlockRegistrySize) { + user.kick(Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + )); return; - FriendlyByteBuf buf = discardedPayload.toBuffer(); - NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); - if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { - int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - user.kick(Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - )); - return; - } - user.setClientModState(true); - } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { - if (dataType.as(Boolean.class).decode(buf)) { - FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); - dataType.writeType(bufPayload); - dataType.as(Boolean.class).encode(bufPayload, true); - user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); - } + } + user.setClientModState(true); + } else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) { + if (dataType.as(Boolean.class).decode(buf)) { + FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); + dataType.writeType(bufPayload); + dataType.as(Boolean.class).encode(bufPayload, true); + user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } } catch (Throwable e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java new file mode 100644 index 000000000..4143eea27 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/UnknownPayload.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public record UnknownPayload(Key channel, ByteBuf rawPayload) implements Payload{ + + public static UnknownPayload from(Object payload) { + try { + Object id = NetworkReflections.field$UnknownPayload$id.get(payload); + ByteBuf data = (ByteBuf) NetworkReflections.field$UnknownPayload$data.get(payload); + Key channel = KeyUtils.resourceLocationToKey(id); + return new UnknownPayload(channel, data); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to create UnknownPayload", e); + return null; + } + } + + @Override + public FriendlyByteBuf toBuffer() { + return new FriendlyByteBuf(rawPayload); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 6c1d427a9..08254bcba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1621,4 +1621,22 @@ public final class NetworkReflections { throw new ReflectionInitException("Failed to initialize HashedStack$STREAM_CODEC", e); } } + + // 1.20.2~1.20.4 + public static final Class clazz$UnknownPayload = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket$UnknownPayload") + ), + VersionHelper.isOrAbove1_20_2() && !VersionHelper.isOrAbove1_20_5() + ); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$id = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ResourceLocation, 0)) + .orElse(null); + + // 1.20.2~1.20.4 + public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) + .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) + .orElse(null); } From ad6bd3ae3caa185bcd8c4593a8bb6c764539cd07 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:32:36 +0800 Subject: [PATCH 12/21] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D1.20.2~?= =?UTF-8?q?1.20.4=E5=8F=91=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 1 - .../plugin/reflection/minecraft/NetworkReflections.java | 9 ++++++++- .../bukkit/plugin/user/BukkitServerPlayer.java | 4 +++- 3 files changed, 11 insertions(+), 3 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 661920946..dcb6b3a7d 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 @@ -1887,7 +1887,6 @@ public class PacketConsumers { try { if (!VersionHelper.isOrAbove1_20_2()) return; Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); - System.out.println(payload.getClass()); Payload clientPayload; if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { clientPayload = DiscardedPayload.from(payload); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index 08254bcba..b5bd1bd0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1248,7 +1248,9 @@ public final class NetworkReflections { ); public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( - ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) + VersionHelper.isOrAbove1_20_2() + ? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload) + : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) ); // 1.20.2+ @@ -1639,4 +1641,9 @@ public final class NetworkReflections { public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload) .map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0)) .orElse(null); + + // 1.20.2~1.20.4 + public static final Constructor constructor$UnknownPayload = Optional.ofNullable(clazz$UnknownPayload) + .map(ReflectionUtils::getTheOnlyConstructor) + .orElse(null); } 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 74430caf7..6bcf22b32 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 @@ -307,7 +307,9 @@ public class BukkitServerPlayer extends Player { try { Object channelKey = KeyUtils.toResourceLocation(channel); Object dataPayload; - if (DiscardedPayload.useNewMethod) { + if (NetworkReflections.clazz$UnknownPayload != null) { + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } else if (DiscardedPayload.useNewMethod) { dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); } else { dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); From 64466257bab1eac0375c666a32d8e283c637e513 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 19 Jul 2025 23:34:23 +0800 Subject: [PATCH 13/21] =?UTF-8?q?fix(network):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 3 +++ 1 file changed, 3 insertions(+) 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 6bcf22b32..db820d674 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 @@ -304,6 +304,9 @@ public class BukkitServerPlayer extends Player { @Override public void sendCustomPayload(Key channel, byte[] data) { + if (!VersionHelper.isOrAbove1_20_2()) { + throw new UnsupportedOperationException("Cannot send custom payload to " + name() + " because the server is running a version below 1.20.2"); + } try { Object channelKey = KeyUtils.toResourceLocation(channel); Object dataPayload; From 70925ee2c98af2acab9acf29ccc51f003bafb8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sun, 20 Jul 2025 00:07:32 +0800 Subject: [PATCH 14/21] fix: style loss --- .../core/util/AdventureHelper.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index f58769a92..f3af38fc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -36,6 +36,20 @@ public class AdventureHelper { private final GsonComponentSerializer gsonComponentSerializer; private final NBTComponentSerializer nbtComponentSerializer; private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build(); + /** + * This iterator slices a component into individual parts that + *
    + *
  • Can be used individually without style loss
  • + *
  • Can be concatenated to form the original component, given that children are dropped
  • + *
+ * Any {@link net.kyori.adventure.text.ComponentIteratorFlag}s are ignored. + */ + private static final ComponentIteratorType SLICER = (component, deque, flags) -> { + final List children = component.children(); + for (int i = children.size() - 1; i >= 0; i--) { + deque.addFirst(children.get(i).applyFallbackStyle(component.style())); + } + }; private AdventureHelper() { this.miniMessage = MiniMessage.builder().build(); @@ -219,17 +233,17 @@ public class AdventureHelper { public static List splitLines(Component component) { List result = new ArrayList<>(1); Component line = Component.empty(); - for (Iterator it = component.replaceText(REPLACE_LF).iterator(ComponentIteratorType.DEPTH_FIRST); it.hasNext(); ) { + for (Iterator it = component.replaceText(REPLACE_LF).iterator(SLICER); it.hasNext(); ) { Component child = it.next().children(Collections.emptyList()); - if (Component.EQUALS.test(child, Component.newline())) { - result.add(line); + if (child instanceof TextComponent text && text.content().equals(Component.newline().content())) { + result.add(line.compact()); line = Component.empty(); } else { line = line.append(child); } } if (Component.IS_NOT_EMPTY.test(line)) { - result.add(line); + result.add(line.compact()); } return result; } From 5abdb8af1d870cca2fbb6406d511f9f8344b3de7 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 20 Jul 2025 00:32:30 +0800 Subject: [PATCH 15/21] =?UTF-8?q?feat(network):=20=E5=AE=8C=E5=96=84sendCu?= =?UTF-8?q?stomPayload=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../minecraft/NetworkReflections.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index b5bd1bd0f..6c11c869e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1250,7 +1250,7 @@ public final class NetworkReflections { public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( VersionHelper.isOrAbove1_20_2() ? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload) - : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0) + : ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$FriendlyByteBuf) ); // 1.20.2+ 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 db820d674..5e78643a6 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 @@ -304,20 +304,22 @@ public class BukkitServerPlayer extends Player { @Override public void sendCustomPayload(Key channel, byte[] data) { - if (!VersionHelper.isOrAbove1_20_2()) { - throw new UnsupportedOperationException("Cannot send custom payload to " + name() + " because the server is running a version below 1.20.2"); - } try { Object channelKey = KeyUtils.toResourceLocation(channel); - Object dataPayload; - if (NetworkReflections.clazz$UnknownPayload != null) { - dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); - } else if (DiscardedPayload.useNewMethod) { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + Object responsePacket; + if (VersionHelper.isOrAbove1_20_2()) { + Object dataPayload; + if (NetworkReflections.clazz$UnknownPayload != null) { + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } else if (DiscardedPayload.useNewMethod) { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + } else { + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + } + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); } else { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelKey, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data))); } - Object responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); this.sendPacket(responsePacket, true); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to send custom payload to " + name(), e); From 107622dea0d719848c5f2246674a63915d10859c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 02:30:11 +0800 Subject: [PATCH 16/21] =?UTF-8?q?=E4=BC=98=E5=8C=96lore=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/block/properties/Properties.java | 2 +- .../core/item/AbstractItemManager.java | 22 +-- .../craftengine/core/item/ItemFactory.java | 3 +- .../core/item/modifier/LoreModification.java | 45 ------ .../core/item/modifier/LoreModifier.java | 55 -------- .../{ => lore}/DynamicLoreModifier.java | 30 ++-- .../item/modifier/lore/LoreModification.java | 39 ++++++ .../modifier/lore/LoreModificationHolder.java | 11 ++ .../core/item/modifier/lore/LoreModifier.java | 128 ++++++++++++++++++ .../core/pack/ResourceLocation.java | 2 +- .../core/util/AdventureHelper.java | 6 +- .../craftengine/core/util/MiscUtils.java | 14 ++ .../core/util/ResourceConfigUtils.java | 9 +- 13 files changed, 217 insertions(+), 149 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java rename core/src/main/java/net/momirealms/craftengine/core/item/modifier/{ => lore}/DynamicLoreModifier.java (63%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java index 5636e7ae9..a54c56afa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.*; import java.util.Map; -public class Properties { +public final class Properties { public static final Key BOOLEAN = Key.of("craftengine:boolean"); public static final Key INT = Key.of("craftengine:int"); public static final Key STRING = Key.of("craftengine:string"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 5aebb5f74..0bb7a59cf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -9,6 +9,8 @@ import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.equipment.*; import net.momirealms.craftengine.core.item.modifier.*; +import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; +import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; @@ -534,26 +536,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new CustomNameModifier<>(name); }, "custom-name", "item-name", "display-name"); } - Function> loreModificationListParser = (obj) -> { - if (obj instanceof List list) { - List modifications = new ArrayList<>(list.size()); - for (Object entry : list) { - if (entry instanceof Map map) { - modifications.add(new LoreModification(ResourceConfigUtils.getAsEnumOrDefault(map.get("action").toString().toUpperCase(Locale.ROOT), LoreModification.Action.class, LoreModification.Action.SET), ResourceConfigUtils.getAsInt(map.get("priority"), "priority"), ResourceConfigUtils.getAsBoolean(map.get("split-lines"), "split-lines"), MiscUtils.getAsStringList(map.get("content")))); - } else { - modifications.add(new LoreModification(List.of(entry.toString()))); - } - } - return modifications; - } - return Collections.emptyList(); - }; - registerDataType((obj) -> new LoreModifier<>(loreModificationListParser.apply(obj)), "lore", "display-lore", "description"); + registerDataType(LoreModifier::createLoreModifier, "lore", "display-lore", "description"); registerDataType((obj) -> { - Map> dynamicLore = new LinkedHashMap<>(); + Map> dynamicLore = new LinkedHashMap<>(); if (obj instanceof Map map) { for (Map.Entry entry : map.entrySet()) { - dynamicLore.put(entry.getKey().toString(), loreModificationListParser.apply(entry.getValue())); + dynamicLore.put(entry.getKey().toString(), LoreModifier.createLoreModifier(entry.getValue())); } } return new DynamicLoreModifier<>(dynamicLore); 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 d403ba310..365582553 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 @@ -16,7 +16,6 @@ import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; @@ -112,7 +111,7 @@ public abstract class ItemFactory, I> { protected void loreComponent(W item, List component) { if (component != null && !component.isEmpty()) { - loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); + loreJson(item, component.stream().map(AdventureHelper::componentToJson).toList()); } else { loreJson(item, null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java deleted file mode 100644 index 45ecd76ae..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModification.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.momirealms.craftengine.core.item.modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.AdventureHelper; -public record LoreModification(Action action, int priority, boolean split, List content) implements Comparable { - public LoreModification(List content) { - this(Action.SET, 0, false, content); - } - public LoreModification(Action action, int priority, boolean split, List content) { - this.action = action; - this.priority = priority; - this.split = split; - if (Config.addNonItalicTag()) { - List processed = new ArrayList<>(content.size()); - for (String arg : content) { - processed.add(arg.startsWith("") ? arg : "" + arg); - } - this.content = processed; - } else { - this.content = content; - } - } - public Stream apply(Stream lore, ItemBuildContext context) { - return switch (action) { - case PREPEND -> Stream.concat(parseContent(context), lore); - case APPEND -> Stream.concat(lore, parseContent(context)); - default -> parseContent(context); - }; - } - private Stream parseContent(ItemBuildContext context) { - Stream parsed = content.stream().map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); - return split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; - } - @Override - public int compareTo(LoreModification other) { - return Integer.compare(priority, other.priority); - } - public enum Action { - SET, PREPEND, APPEND - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java deleted file mode 100644 index f76c1bb60..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.momirealms.craftengine.core.item.modifier; - -import java.util.ArrayList; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; - -import java.util.List; - -public class LoreModifier implements ItemDataModifier { - private final List argument; - - public LoreModifier(List argument) { - argument = new ArrayList<>(argument); - argument.sort(null); - this.argument = List.copyOf(argument); - } - - @Override - public String name() { - return "lore"; - } - - @Override - public Item apply(Item item, ItemBuildContext context) { - item.loreComponent(argument.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); - return item; - } - - @Override - public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); - if (previous != null) { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } else { - Tag previous = item.getTag("display", "Lore"); - if (previous != null) { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); - } else { - networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); - } - } - return item; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java similarity index 63% rename from core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java rename to core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java index fd7bd99d3..5f36228d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/DynamicLoreModifier.java @@ -1,32 +1,29 @@ -package net.momirealms.craftengine.core.item.modifier; +package net.momirealms.craftengine.core.item.modifier.lore; -import java.util.stream.Stream; -import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Optional; -public class DynamicLoreModifier implements ItemDataModifier { +public final class DynamicLoreModifier implements ItemDataModifier { public static final String CONTEXT_TAG_KEY = "craftengine:display_context"; - private final Map> displayContexts; - private final String defaultContext; + private final Map> displayContexts; + private final LoreModifier defaultModifier; - public DynamicLoreModifier(Map> displayContexts) { - this.defaultContext = displayContexts.keySet().iterator().next(); + public DynamicLoreModifier(Map> displayContexts) { this.displayContexts = displayContexts; + this.defaultModifier = displayContexts.values().iterator().next(); } - public Map> displayContexts() { - return Collections.unmodifiableMap(this.displayContexts); + public Map> displayContexts() { + return displayContexts; } @Override @@ -36,13 +33,12 @@ public class DynamicLoreModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultContext).toString(); - List lore = this.displayContexts.get(displayContext); + String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultModifier).toString(); + LoreModifier lore = this.displayContexts.get(displayContext); if (lore == null) { - lore = this.displayContexts.get(this.defaultContext); + lore = this.defaultModifier; } - item.loreComponent(lore.stream().reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); - return item; + return lore.apply(item, context); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java new file mode 100644 index 000000000..0b6b8ce34 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModification.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.TriFunction; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// todo 可以考虑未来添加条件系统 +public record LoreModification(Operation operation, boolean split, String[] content) { + + public Stream apply(Stream lore, ItemBuildContext context) { + return this.operation.function.apply(lore, context, this); + } + + public Stream parseAsStream(ItemBuildContext context) { + Stream parsed = Arrays.stream(this.content).map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers())); + return this.split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; + } + + public List parseAsList(ItemBuildContext context) { + return this.parseAsStream(context).collect(Collectors.toList()); + } + + public enum Operation { + APPEND((s, c, modification) -> Stream.concat(s, modification.parseAsStream(c))), + PREPEND((s, c, modification) -> Stream.concat(modification.parseAsStream(c), s)); + + private final TriFunction, ItemBuildContext, LoreModification, Stream> function; + + Operation(TriFunction, ItemBuildContext, LoreModification, Stream> function) { + this.function = function; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java new file mode 100644 index 000000000..7e2c4df28 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModificationHolder.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import org.jetbrains.annotations.NotNull; + +public record LoreModificationHolder(LoreModification modification, int priority) implements Comparable { + + @Override + public int compareTo(@NotNull LoreModificationHolder o) { + return Integer.compare(priority, o.priority); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java new file mode 100644 index 000000000..61c25a25d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -0,0 +1,128 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.*; +import java.util.stream.Stream; + +public sealed interface LoreModifier extends ItemDataModifier + permits LoreModifier.EmptyLoreModifier, LoreModifier.CompositeLoreModifier, LoreModifier.DoubleLoreModifier, LoreModifier.SingleLoreModifier { + + @Override + default String name() { + return "lore"; + } + + @Override + default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE); + if (previous != null) networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + else networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } else { + Tag previous = item.getTag("display", "Lore"); + if (previous != null) networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + else networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + return item; + } + + static LoreModifier createLoreModifier(Object arg) { + List rawLoreData = MiscUtils.getAsList(arg, Object.class); + List lore = new ArrayList<>(); + label_all_string_check: { + for (Object o : rawLoreData) { + if (o instanceof Map) { + break label_all_string_check; + } else { + lore.add(String.valueOf(o)); + } + } + return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, lore.toArray(new String[0]))); + } + + List modifications = new ArrayList<>(rawLoreData.size() + 1); + int lastPriority = 0; + for (Object o : rawLoreData) { + if (o instanceof Map complexLore) { + String[] content = MiscUtils.getAsStringArray(complexLore.get("content")); + LoreModification.Operation operation = ResourceConfigUtils.getAsEnum(Optional.ofNullable(complexLore.get("operation")).map(String::valueOf).orElse(null), LoreModification.Operation.class, LoreModification.Operation.APPEND); + lastPriority = Optional.ofNullable(complexLore.get("priority")).map(it -> ResourceConfigUtils.getAsInt(it, "priority")).orElse(lastPriority); + boolean split = ResourceConfigUtils.getAsBoolean(complexLore.get("split-lines"), "split-lines"); + modifications.add(new LoreModificationHolder(new LoreModification(operation, split, content), lastPriority)); + } + } + modifications.sort(LoreModificationHolder::compareTo); + return switch (modifications.size()) { + case 0 -> new EmptyLoreModifier<>(); + case 1 -> new SingleLoreModifier<>(modifications.get(0).modification()); + case 2 -> new DoubleLoreModifier<>(modifications.get(0).modification(), modifications.get(1).modification()); + default -> new CompositeLoreModifier<>(modifications.stream().map(LoreModificationHolder::modification).toArray(LoreModification[]::new)); + }; + } + + non-sealed class EmptyLoreModifier implements LoreModifier { + + @Override + public Item apply(Item item, ItemBuildContext context) { + return item; + } + } + + non-sealed class SingleLoreModifier implements LoreModifier { + private final LoreModification modification; + + public SingleLoreModifier(LoreModification modification) { + this.modification = modification; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.loreComponent(this.modification.parseAsList(context)); + return item; + } + } + + non-sealed class DoubleLoreModifier implements LoreModifier { + private final LoreModification modification1; + private final LoreModification modification2; + + public DoubleLoreModifier(LoreModification m1, LoreModification m2) { + this.modification1 = m1; + this.modification2 = m2; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + Stream start = Stream.empty(); + this.modification1.apply(start, context); + this.modification2.apply(start, context); + item.loreComponent(start.toList()); + return item; + } + } + + non-sealed class CompositeLoreModifier implements LoreModifier { + private final LoreModification[] modifications; + + public CompositeLoreModifier(LoreModification... modifications) { + this.modifications = modifications; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.loreComponent(Arrays.stream(this.modifications).reduce(Stream.empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList()); + return item; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java index 4e580df18..1d6c48e33 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java @@ -20,7 +20,7 @@ public final class ResourceLocation { } public static boolean isValidNamespace(String namespace) { - for(int i = 0; i < namespace.length(); ++i) { + for (int i = 0; i < namespace.length(); ++i) { if (!validNamespaceChar(namespace.charAt(i))) { return false; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index f3af38fc8..e988d1f68 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -1,10 +1,6 @@ package net.momirealms.craftengine.core.util; import com.google.gson.JsonElement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; @@ -21,7 +17,7 @@ import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.adventure.NBTComponentSerializer; import net.momirealms.sparrow.nbt.adventure.NBTSerializerOptions; -import java.util.Map; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; 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 f3b1bf95c..54195dff8 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 @@ -51,6 +51,20 @@ public class MiscUtils { return list; } + public static String[] getAsStringArray(Object o) { + if (o instanceof List list) { + String[] array = new String[list.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = list.get(i).toString(); + } + return array; + } else if (o != null) { + return new String[]{o.toString()}; + } else { + return new String[0]; + } + } + @SuppressWarnings("unchecked") public static List getAsList(Object o, Class clazz) { if (o instanceof List list) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index a9671f7de..dfdaa4317 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -5,10 +5,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; @@ -20,12 +17,12 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } - public static > E getAsEnumOrDefault(Object o, Class clazz, E defaultValue) { + public static > E getAsEnum(Object o, Class clazz, E defaultValue) { if (o == null) { return defaultValue; } try { - return Enum.valueOf(clazz, o.toString()); + return Enum.valueOf(clazz, o.toString().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return defaultValue; } From 994ea7fc4d18adb7686553fb3b86ef40a8e73b5e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 02:36:09 +0800 Subject: [PATCH 17/21] =?UTF-8?q?=E6=8F=90=E5=8D=87=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/modifier/lore/LoreModifier.java | 9 +++++---- gradle.properties | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java index 61c25a25d..912e4d099 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -39,16 +39,17 @@ public sealed interface LoreModifier extends ItemDataModifier static LoreModifier createLoreModifier(Object arg) { List rawLoreData = MiscUtils.getAsList(arg, Object.class); - List lore = new ArrayList<>(); + String[] rawLore = new String[rawLoreData.size()]; label_all_string_check: { - for (Object o : rawLoreData) { + for (int i = 0; i < rawLore.length; i++) { + Object o = rawLoreData.get(i); if (o instanceof Map) { break label_all_string_check; } else { - lore.add(String.valueOf(o)); + rawLore[i] = o.toString(); } } - return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, lore.toArray(new String[0]))); + return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, rawLore)); } List modifications = new ArrayList<>(rawLoreData.size() + 1); diff --git a/gradle.properties b/gradle.properties index ef51839f9..1e4e87a6e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.60.3 -config_version=42 +project_version=0.0.60.4 +config_version=43 lang_version=22 project_group=net.momirealms latest_supported_version=1.21.8 From 2ee574a83db6dce5406fd90fa443918a344e97f2 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 20 Jul 2025 04:45:19 +0800 Subject: [PATCH 18/21] =?UTF-8?q?feat(core):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=20MythicMobs=20=E6=8A=80=E8=83=BD=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 7 +++ .../compatibility/mythicmobs/SkillHelper.java | 29 +++++++++++ .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + .../compatibility/CompatibilityManager.java | 2 + .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../function/MythicMobsSkillFunction.java | 48 +++++++++++++++++++ 8 files changed, 90 insertions(+) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.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 656ba4791..56248a777 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 @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterM import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.SkillHelper; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; @@ -39,6 +40,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map levelerProviders; private boolean hasPlaceholderAPI; private boolean hasViaVersion; + private SkillHelper skillExecute; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -136,6 +138,11 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } } + @Override + public void skillExecute(String skill, float power, Player player) { + SkillHelper.execute(skill, power, player); + } + @Override public void registerLevelerProvider(String plugin, LevelerProvider provider) { this.levelerProviders.put(plugin, provider); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java new file mode 100644 index 000000000..32162b6d2 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.bukkit.compatibility.mythicmobs; + +import io.lumine.mythic.bukkit.MythicBukkit; +import io.lumine.mythic.core.utils.MythicUtil; +import net.momirealms.craftengine.core.entity.player.Player; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; + +public class SkillHelper { + + public static void execute(String skill, float power, Player player) { + org.bukkit.entity.Player casterPlayer = (org.bukkit.entity.Player) player.platformPlayer(); + Location location = casterPlayer.getLocation(); + LivingEntity target = MythicUtil.getTargetedEntity(casterPlayer); + List targets = new ArrayList<>(); + List locations = null; + if (target != null) { + targets.add(target); + locations = List.of(target.getLocation()); + } + try (MythicBukkit mm = MythicBukkit.inst()) { + mm.getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); + } + } +} diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 56a24d8f5..375cfd1f0 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -393,6 +393,7 @@ warning.config.function.potion_effect.missing_potion_effect: "Issue foun warning.config.function.set_cooldown.missing_time: "Issue found in file - The config '' is missing the required 'time' argument for 'set_cooldown' function." warning.config.function.set_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'set_cooldown' function." warning.config.function.remove_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'remove_cooldown' function." +warning.config.function.mythic_mobs_skill.missing_skill: "Issue found in file - The config '' is missing the required 'skill' argument for 'mythic_mobs_skill' 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 ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 11b6758f2..91bfbf70c 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -391,6 +391,7 @@ warning.config.function.potion_effect.missing_potion_effect: "在文件 warning.config.function.set_cooldown.missing_time: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'time' 参数" warning.config.function.set_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'id' 参数" warning.config.function.remove_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'remove_cooldown' 函数必需的 'id' 参数" +warning.config.function.mythic_mobs_skill.missing_skill: "在文件 中发现问题 - 配置项 '' 缺少 'mythic_mobs_skill' 函数必需的 'skill' 参数" warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 83b15f39b..9459acdfc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -34,4 +34,6 @@ public interface CompatibilityManager { String parse(Player player1, Player player2, String text); int getPlayerProtocolVersion(UUID uuid); + + void skillExecute(String skill, float power, Player player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 1541a39d2..c61dba386 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -38,6 +38,7 @@ public class EventFunctions { register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_COOLDOWN, new SetCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.REMOVE_COOLDOWN, new RemoveCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.MYTHIC_MOBS_SKILL, new MythicMobsSkillFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { 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 8c0bc6435..055e3260a 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 @@ -27,4 +27,5 @@ public final class CommonFunctions { public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); public static final Key LEVELER_EXP = Key.of("craftengine:leveler_exp"); + public static final Key MYTHIC_MOBS_SKILL = Key.of("craftengine:mythic_mobs_skill"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java new file mode 100644 index 000000000..bb4a61c85 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +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.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class MythicMobsSkillFunction extends AbstractConditionalFunction { + private final String skill; + private final float power; + + public MythicMobsSkillFunction(String skill, float power, List> predicates) { + super(predicates); + this.skill = skill; + this.power = power; + } + + @Override + protected void runInternal(CTX ctx) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + CraftEngine.instance().compatibilityManager().skillExecute(this.skill, this.power, it); + }); + } + + @Override + public Key type() { + return CommonFunctions.MYTHIC_MOBS_SKILL; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map args) { + String skill = ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("skill"), "warning.config.function.mythic_mobs_skill.missing_skill"); + float power = ResourceConfigUtils.getAsFloat(args.getOrDefault("power", 1.0), "power"); + return new MythicMobsSkillFunction<>(skill, power, getPredicates(args)); + } + } +} From 56226e1ad99873ac4609c4c0e752d2a1e4022d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=91=95=E1=96=87EE=E1=91=ADY=E1=91=95=E1=96=87EE?= =?UTF-8?q?=E1=91=ADE=E1=96=87?= <3404705272@qq.com> Date: Sun, 20 Jul 2025 21:08:09 +0800 Subject: [PATCH 19/21] fix: DoubleLoreModifier --- .../craftengine/core/item/modifier/lore/LoreModifier.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java index 912e4d099..8e998115d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/LoreModifier.java @@ -105,10 +105,7 @@ public sealed interface LoreModifier extends ItemDataModifier @Override public Item apply(Item item, ItemBuildContext context) { - Stream start = Stream.empty(); - this.modification1.apply(start, context); - this.modification2.apply(start, context); - item.loreComponent(start.toList()); + item.loreComponent(this.modification2.apply(this.modification1.apply(Stream.empty(), context), context).toList()); return item; } } From bee6d258b4ca8b99fc090d4cb87b6e0ec82bd158 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 20 Jul 2025 21:23:32 +0800 Subject: [PATCH 20/21] =?UTF-8?q?=E4=B9=9F=E8=AE=B8=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=86FAWE=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 12 +- ...ngineItemDrop.java => MythicItemDrop.java} | 4 +- ...tener.java => MythicItemDropListener.java} | 6 +- ...killHelper.java => MythicSkillHelper.java} | 6 +- .../worldedit/FastAsyncWorldEditDelegate.java | 38 +++--- .../bukkit/world/BukkitWorldManager.java | 118 +++++++++--------- .../compatibility/CompatibilityManager.java | 2 +- .../function/MythicMobsSkillFunction.java | 2 +- .../craftengine/core/world/WorldManager.java | 2 + gradle.properties | 2 +- 10 files changed, 103 insertions(+), 89 deletions(-) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{CraftEngineItemDrop.java => MythicItemDrop.java} (93%) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{MythicMobsListener.java => MythicItemDropListener.java} (83%) rename bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/{SkillHelper.java => MythicSkillHelper.java} (81%) 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 56248a777..a341e41fe 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 @@ -10,8 +10,8 @@ import net.momirealms.craftengine.bukkit.compatibility.leveler.*; import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; -import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener; -import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.SkillHelper; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicSkillHelper; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; @@ -40,7 +40,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map levelerProviders; private boolean hasPlaceholderAPI; private boolean hasViaVersion; - private SkillHelper skillExecute; + private MythicSkillHelper skillExecute; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -133,14 +133,14 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } if (this.isPluginEnabled("MythicMobs")) { BukkitItemManager.instance().registerExternalItemSource(new MythicMobsSource()); - new MythicMobsListener(this.plugin); + new MythicItemDropListener(this.plugin); logHook("MythicMobs"); } } @Override - public void skillExecute(String skill, float power, Player player) { - SkillHelper.execute(skill, power, player); + public void executeMMSkill(String skill, float power, Player player) { + MythicSkillHelper.execute(skill, power, player); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java similarity index 93% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java index 9c582cf1d..8b151df79 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java @@ -21,12 +21,12 @@ import org.bukkit.inventory.ItemStack; import java.lang.reflect.Constructor; -public class CraftEngineItemDrop extends ItemDrop implements IItemDrop { +public class MythicItemDrop extends ItemDrop implements IItemDrop { private final CustomItem customItem; private static final Constructor constructor$BukkitItemStack = ReflectionUtils.getConstructor(BukkitItemStack.class, ItemStack.class); private static final boolean useReflection = constructor$BukkitItemStack != null; - public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem customItem) { + public MythicItemDrop(String line, MythicLineConfig config, CustomItem customItem) { super(line, config); this.customItem = customItem; } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java similarity index 83% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java index 22101993b..96cacc0b7 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java @@ -8,10 +8,10 @@ import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -public class MythicMobsListener implements Listener { +public class MythicItemDropListener implements Listener { private final BukkitCraftEngine plugin; - public MythicMobsListener(BukkitCraftEngine plugin) { + public MythicItemDropListener(BukkitCraftEngine plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); } @@ -24,7 +24,7 @@ public class MythicMobsListener implements Listener { this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> { String line = event.getContainer().getConfigLine(); MythicLineConfig config = event.getConfig(); - event.register(new CraftEngineItemDrop(line, config, customItem)); + event.register(new MythicItemDrop(line, config, customItem)); }); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java similarity index 81% rename from bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java index 32162b6d2..8ac5a7356 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/SkillHelper.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicSkillHelper.java @@ -10,7 +10,7 @@ import org.bukkit.entity.LivingEntity; import java.util.ArrayList; import java.util.List; -public class SkillHelper { +public final class MythicSkillHelper { public static void execute(String skill, float power, Player player) { org.bukkit.entity.Player casterPlayer = (org.bukkit.entity.Player) player.platformPlayer(); @@ -22,8 +22,6 @@ public class SkillHelper { targets.add(target); locations = List.of(target.getLocation()); } - try (MythicBukkit mm = MythicBukkit.inst()) { - mm.getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); - } + MythicBukkit.inst().getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index b03240f25..476e6370c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -1,9 +1,12 @@ package net.momirealms.craftengine.bukkit.compatibility.worldedit; +import com.fastasyncworldedit.bukkit.FaweBukkitWorld; import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; +import com.fastasyncworldedit.bukkit.adapter.NMSAdapter; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; +import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.ExtentTraverser; import com.fastasyncworldedit.core.util.ProcessorTraverser; import com.sk89q.worldedit.EditSession; @@ -24,6 +27,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.EmptyBlock; @@ -41,6 +45,8 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import static java.util.Objects.requireNonNull; @@ -89,12 +95,14 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { if (levelChunk != null) { Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); CESection[] ceSections = ceChunk.sections(); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - int finalI = i; - WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), - (injected) -> sections[finalI] = injected); + synchronized (sections) { + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + int finalI = i; + WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); + } } } } @@ -174,18 +182,18 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { @Override public @Nullable Operation commit() { - Operation operation = super.commit(); saveAllChunks(); + Operation operation = super.commit(); List chunks = new ArrayList<>(this.brokenChunks); this.brokenChunks.clear(); - Object worldServer = this.ceWorld.world().serverWorld(); - Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); - for (ChunkPos chunk : chunks) { - CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey()); - // only inject loaded chunks - if (loaded == null) continue; - injectLevelChunk(chunkSource, loaded); - } + Object worldServer = this.ceWorld.world().serverWorld(); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + for (ChunkPos chunk : chunks) { + CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey()); + // only inject loaded chunks + if (loaded == null) continue; + injectLevelChunk(chunkSource, loaded); + } return operation; } 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 61aa6dabb..bd04de0e4 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 @@ -88,6 +88,11 @@ public class BukkitWorldManager implements WorldManager, Listener { } } + @Override + public CEWorld[] getWorlds() { + return this.worldArray; + } + private void resetWorldArray() { this.worldArray = this.worlds.values().toArray(new CEWorld[0]); } @@ -218,7 +223,6 @@ public class BukkitWorldManager implements WorldManager, Listener { this.lastVisitedUUID = null; } this.resetWorldArray(); - } finally { this.worldMapLock.writeLock().unlock(); } @@ -328,74 +332,76 @@ public class BukkitWorldManager implements WorldManager, Listener { Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - if (Config.syncCustomBlocks()) { - Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); - Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer); - Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data); - boolean requiresSync = false; - if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) { - Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette); - if (BlockStateUtils.isCustomBlock(onlyBlockState)) { + synchronized (sections) { + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + if (Config.syncCustomBlocks()) { + Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); + Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer); + Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data); + boolean requiresSync = false; + if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) { + Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette); + if (BlockStateUtils.isCustomBlock(onlyBlockState)) { + requiresSync = true; + } + } else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) { + Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette); + for (Object blockState : blockStates) { + if (blockState != null) { + if (BlockStateUtils.isCustomBlock(blockState)) { + requiresSync = true; + break; + } + } + } + } else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) { + Object biMap = CoreReflections.field$HashMapPalette$values.get(palette); + Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap); + for (Object blockState : blockStates) { + if (blockState != null) { + if (BlockStateUtils.isCustomBlock(blockState)) { + requiresSync = true; + break; + } + } + } + } else { requiresSync = true; } - } else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) { - Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette); - for (Object blockState : blockStates) { - if (blockState != null) { - if (BlockStateUtils.isCustomBlock(blockState)) { - requiresSync = true; - break; - } - } - } - } else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) { - Object biMap = CoreReflections.field$HashMapPalette$values.get(palette); - Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap); - for (Object blockState : blockStates) { - if (blockState != null) { - if (BlockStateUtils.isCustomBlock(blockState)) { - requiresSync = true; - break; - } - } - } - } else { - requiresSync = true; - } - if (requiresSync) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z); - Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState); - if (optionalCustomState.isPresent()) { - ceSection.setBlockState(x, y, z, optionalCustomState.get()); + if (requiresSync) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z); + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState); + if (optionalCustomState.isPresent()) { + ceSection.setBlockState(x, y, z, optionalCustomState.get()); + } } } } } } - } - if (Config.restoreCustomBlocks()) { - if (!ceSection.statesContainer().isEmpty()) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - ImmutableBlockState customState = ceSection.getBlockState(x, y, z); - if (!customState.isEmpty() && customState.customBlockState() != null) { - FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false); + if (Config.restoreCustomBlocks()) { + if (!ceSection.statesContainer().isEmpty()) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + ImmutableBlockState customState = ceSection.getBlockState(x, y, z); + if (!customState.isEmpty() && customState.customBlockState() != null) { + FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false); + } } } } } } + int finalI = i; + WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + (injected) -> sections[finalI] = injected); } - int finalI = i; - WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), - (injected) -> sections[finalI] = injected); } if (Config.enableRecipeSystem()) { @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 9459acdfc..f38d30c1f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -35,5 +35,5 @@ public interface CompatibilityManager { int getPlayerProtocolVersion(UUID uuid); - void skillExecute(String skill, float power, Player player); + void executeMMSkill(String skill, float power, Player player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java index bb4a61c85..031ed08da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MythicMobsSkillFunction.java @@ -23,7 +23,7 @@ public class MythicMobsSkillFunction extends AbstractCondit @Override protected void runInternal(CTX ctx) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { - CraftEngine.instance().compatibilityManager().skillExecute(this.skill, this.power, it); + CraftEngine.instance().compatibilityManager().executeMMSkill(this.skill, this.power, it); }); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 5c83b592b..d6a746cbd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -13,6 +13,8 @@ public interface WorldManager extends Manageable { CEWorld getWorld(UUID uuid); + CEWorld[] getWorlds(); + void loadWorld(World world); void loadWorld(CEWorld world); diff --git a/gradle.properties b/gradle.properties index 1e4e87a6e..2c126627e 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.60.4 +project_version=0.0.60.5 config_version=43 lang_version=22 project_group=net.momirealms From 8de1acc3ee5712e01eb9f55c00b5e41e7fe20184 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 21 Jul 2025 04:54:45 +0800 Subject: [PATCH 21/21] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=BD=BF=E7=94=A8secti?= =?UTF-8?q?on=E4=BF=AE=E5=A4=8D=E6=BD=9C=E5=9C=A8=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../worldedit/FastAsyncWorldEditDelegate.java | 7 +++---- common-files/src/main/resources/config.yml | 6 ++---- .../craftengine/core/item/AbstractItemManager.java | 1 + .../momirealms/craftengine/core/world/chunk/CEChunk.java | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index 476e6370c..04669495f 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -45,8 +45,6 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.lang.reflect.Method; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import static java.util.Objects.requireNonNull; @@ -222,11 +220,12 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { try { CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ)) .orElse(this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ))); + CESection ceSection = ceChunk.sectionById(SectionPos.blockToSectionCoord(blockY)); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(newStateId); if (immutableBlockState == null) { - ceChunk.setBlockState(blockX, blockY, blockZ, EmptyBlock.STATE); + ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, EmptyBlock.STATE); } else { - ceChunk.setBlockState(blockX, blockY, blockZ, immutableBlockState); + ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, immutableBlockState); } this.chunksToSave.add(ceChunk); } catch (IOException e) { diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 5acc916c1..9222673b8 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -84,8 +84,6 @@ 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: @@ -380,9 +378,9 @@ chunk-system: # Settings for injection injection: # Requires a restart to apply - # SECTION: Inject the LevelChunkSection (Faster & Experimental) since 0.0.53 + # SECTION: Inject the LevelChunkSection # PALETTE: Inject the PalettedContainer - target: PALETTE + target: SECTION # Enables faster injection method # Note: May not work with certain server forks that alter chunk class structure (In most cases it won't conflict) use-fast-method: false diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 0bb7a59cf..6865d2cf7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.pack.AbstractPackManager; 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.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java index 45b0a52b8..fb00cc0dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java @@ -113,7 +113,7 @@ public class CEChunk { return this.sections[index]; } - @Nullable + @NotNull public CESection sectionById(int sectionId) { return this.sections[sectionIndex(sectionId)]; }