From aa2988b8c81aba289c28d68a7d6937f49f07d62a Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 6 Aug 2025 12:04:28 +0800 Subject: [PATCH 01/57] =?UTF-8?q?refactor(furniture):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=B6=E5=85=B7=E5=87=BD=E6=95=B0=E7=94=9F=E6=88=90=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=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 --- .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../function/RemoveFurnitureFunction.java | 48 +++++++++++---- .../function/ReplaceFurnitureFunction.java | 58 ++++++++++--------- .../function/SpawnFurnitureFunction.java | 45 +++++++------- 5 files changed, 98 insertions(+), 57 deletions(-) diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 8a428d817..fedd0c09a 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -401,6 +401,8 @@ warning.config.function.set_cooldown.missing_time: "Issue found in file 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.function.spawn_furniture.missing_furniture_id: "Issue found in file - The config '' is missing the required 'furniture-id' argument for 'spawn_furniture' function." +warning.config.function.replace_furniture.missing_furniture_id: "Issue found in file - The config '' is missing the required 'furniture-id' argument for 'replace_furniture' 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 3512ddf1b..7a22c1732 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -401,6 +401,8 @@ warning.config.function.set_cooldown.missing_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.function.spawn_furniture.missing_furniture_id: "在文件 中发现问题 - 配置项 '' 缺少 'spawn_furniture' 函数必需的 'furniture-id' 参数" +warning.config.function.replace_furniture.missing_furniture_id: "在文件 中发现问题 - 配置项 '' 缺少 'replace_furniture' 函数必需的 'furniture-id' 参数" 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/context/function/RemoveFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java index 0fa908dec..88a2eb2ff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java @@ -1,11 +1,19 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import java.util.List; @@ -24,18 +32,36 @@ public class RemoveFurnitureFunction extends AbstractCondit @Override public void runInternal(CTX ctx) { - Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); - if (optionalWorldPosition.isPresent()) { - // Search for furniture in the context - Optional optionalFurniture = ctx.getOptionalParameter(DirectContextParameters.FURNITURE); - if (optionalFurniture.isPresent()) { - Furniture furniture = optionalFurniture.get(); - if (furniture.isValid()) { - furniture.destroy(); - // TODO: Implement logic to drop loot and play sounds - // using this.dropLoot and this.playSound when necessary - } + ctx.getOptionalParameter(DirectContextParameters.FURNITURE).ifPresent(furniture -> removeFurniture(ctx, furniture, dropLoot, playSound)); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void removeFurniture(Context ctx, Furniture furniture, boolean dropLoot, boolean playSound) { + if (!furniture.isValid()) return; + WorldPosition position = furniture.position(); + World world = position.world(); + furniture.destroy(); + LootTable lootTable = furniture.config().lootTable(); + if (dropLoot && lootTable != null) { + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position) + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null)); + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + Player player = optionalPlayer.orElse(null); + if (player != null) { + Item itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND); + builder.withParameter(DirectContextParameters.PLAYER, player) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand.isEmpty() ? null : itemInHand); } + List> items = lootTable.getRandomItems(builder.build(), world, player); + for (Item item : items) { + world.dropItemNaturally(position, item); + } + } + if (playSound) { + SoundData breakSound = furniture.config().settings().sounds().breakSound(); + world.playSound(position, breakSound.id(), breakSound.volume().get(), breakSound.pitch().get(), SoundSource.BLOCK); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java index 171674596..ab7e278ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java @@ -4,14 +4,22 @@ import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootTable; 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.ContextHolder; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import java.util.List; @@ -29,9 +37,18 @@ public class ReplaceFurnitureFunction extends AbstractCondi private final boolean dropLoot; private final boolean playSound; - public ReplaceFurnitureFunction(Key newFurnitureId, NumberProvider x, NumberProvider y, NumberProvider z, - NumberProvider pitch, NumberProvider yaw, AnchorType anchorType, - boolean dropLoot, boolean playSound, List> predicates) { + public ReplaceFurnitureFunction( + Key newFurnitureId, + NumberProvider x, + NumberProvider y, + NumberProvider z, + NumberProvider pitch, + NumberProvider yaw, + AnchorType anchorType, + boolean dropLoot, + boolean playSound, + List> predicates + ) { super(predicates); this.newFurnitureId = newFurnitureId; this.x = x; @@ -48,34 +65,24 @@ public class ReplaceFurnitureFunction extends AbstractCondi public void runInternal(CTX ctx) { Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); Optional optionalOldFurniture = ctx.getOptionalParameter(DirectContextParameters.FURNITURE); - + if (optionalWorldPosition.isPresent() && optionalOldFurniture.isPresent()) { Furniture oldFurniture = optionalOldFurniture.get(); - + WorldPosition worldPosition = optionalWorldPosition.get(); + // Get the new position or use the current furniture position double xPos = this.x.getDouble(ctx); double yPos = this.y.getDouble(ctx); double zPos = this.z.getDouble(ctx); float pitchValue = this.pitch.getFloat(ctx); float yawValue = this.yaw.getFloat(ctx); - - WorldPosition newPosition = new WorldPosition(optionalWorldPosition.get().world(), xPos, yPos, zPos, pitchValue, yawValue); - - // Get the new furniture - Optional optionalNewFurniture = CraftEngine.instance().furnitureManager().furnitureById(this.newFurnitureId); - if (optionalNewFurniture.isPresent()) { - CustomFurniture newFurniture = optionalNewFurniture.get(); - AnchorType anchor = this.anchorType != null ? this.anchorType : newFurniture.getAnyAnchorType(); - - // Remove the old furniture - if (oldFurniture.isValid()) { - oldFurniture.destroy(); - } - - // Place the new furniture - FurnitureExtraData extraData = FurnitureExtraData.builder().anchorType(anchor).build(); - CraftEngine.instance().furnitureManager().place(newPosition, newFurniture, extraData, this.playSound); - } + WorldPosition newPosition = new WorldPosition(worldPosition.world(), xPos, yPos, zPos, pitchValue, yawValue); + + // Remove the old furniture + RemoveFurnitureFunction.removeFurniture(ctx, oldFurniture, dropLoot, playSound); + + // Place the new furniture + SpawnFurnitureFunction.spawnFurniture(this.newFurnitureId, newPosition, this.anchorType, this.playSound); } } @@ -92,14 +99,13 @@ public class ReplaceFurnitureFunction extends AbstractCondi @Override public Function create(Map arguments) { - String furnitureIdStr = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.replace_furniture.missing_furniture_id"); - Key furnitureId = Key.of(furnitureIdStr); + Key furnitureId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.replace_furniture.missing_furniture_id")); NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", "")); NumberProvider yaw = NumberProviders.fromObject(arguments.getOrDefault("yaw", "")); - AnchorType anchorType = Optional.ofNullable(arguments.get("anchor-type")).map(o -> AnchorType.valueOf(o.toString().toUpperCase())).orElse(null); + AnchorType anchorType = ResourceConfigUtils.getAsEnum(arguments.get("anchor-type"), AnchorType.class, null); boolean dropLoot = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("drop-loot", true), "drop-loot"); boolean playSound = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("play-sound", true), "play-sound"); return new ReplaceFurnitureFunction<>(furnitureId, x, y, z, pitch, yaw, anchorType, dropLoot, playSound, getPredicates(arguments)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java index f3234e792..66b527272 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.furniture.AnchorType; -import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; @@ -28,9 +27,17 @@ public class SpawnFurnitureFunction extends AbstractConditi private final AnchorType anchorType; private final boolean playSound; - public SpawnFurnitureFunction(Key furnitureId, NumberProvider x, NumberProvider y, NumberProvider z, - NumberProvider pitch, NumberProvider yaw, AnchorType anchorType, - boolean playSound, List> predicates) { + public SpawnFurnitureFunction( + Key furnitureId, + NumberProvider x, + NumberProvider y, + NumberProvider z, + NumberProvider pitch, + NumberProvider yaw, + AnchorType anchorType, + boolean playSound, + List> predicates + ) { super(predicates); this.furnitureId = furnitureId; this.x = x; @@ -44,25 +51,24 @@ public class SpawnFurnitureFunction extends AbstractConditi @Override public void runInternal(CTX ctx) { - Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); - if (optionalWorldPosition.isPresent()) { - World world = optionalWorldPosition.get().world(); + ctx.getOptionalParameter(DirectContextParameters.POSITION).ifPresent(worldPosition -> { + World world = worldPosition.world(); double xPos = this.x.getDouble(ctx); double yPos = this.y.getDouble(ctx); double zPos = this.z.getDouble(ctx); float pitchValue = this.pitch.getFloat(ctx); float yawValue = this.yaw.getFloat(ctx); - WorldPosition position = new WorldPosition(world, xPos, yPos, zPos, pitchValue, yawValue); - - Optional optionalFurniture = CraftEngine.instance().furnitureManager().furnitureById(this.furnitureId); - if (optionalFurniture.isPresent()) { - CustomFurniture furniture = optionalFurniture.get(); - AnchorType anchor = this.anchorType != null ? this.anchorType : furniture.getAnyAnchorType(); - FurnitureExtraData extraData = FurnitureExtraData.builder().anchorType(anchor).build(); - CraftEngine.instance().furnitureManager().place(position, furniture, extraData, this.playSound); - } - } + spawnFurniture(this.furnitureId, position, this.anchorType, this.playSound); + }); + } + + public static void spawnFurniture(Key furnitureId, WorldPosition position, AnchorType anchorType, boolean playSound) { + CraftEngine.instance().furnitureManager().furnitureById(furnitureId).ifPresent(furniture -> { + AnchorType anchor = Optional.ofNullable(anchorType).orElse(furniture.getAnyAnchorType()); + FurnitureExtraData extraData = FurnitureExtraData.builder().anchorType(anchor).build(); + CraftEngine.instance().furnitureManager().place(position, furniture, extraData, playSound); + }); } @Override @@ -78,14 +84,13 @@ public class SpawnFurnitureFunction extends AbstractConditi @Override public Function create(Map arguments) { - String furnitureIdStr = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.spawn_furniture.missing_furniture_id"); - Key furnitureId = Key.of(furnitureIdStr); + Key furnitureId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.spawn_furniture.missing_furniture_id")); NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", "")); NumberProvider yaw = NumberProviders.fromObject(arguments.getOrDefault("yaw", "")); - AnchorType anchorType = Optional.ofNullable(arguments.get("anchor-type")).map(o -> AnchorType.valueOf(o.toString().toUpperCase())).orElse(null); + AnchorType anchorType = ResourceConfigUtils.getAsEnum(arguments.get("anchor-type"), AnchorType.class, null); boolean playSound = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("play-sound", true), "play-sound"); return new SpawnFurnitureFunction<>(furnitureId, x, y, z, pitch, yaw, anchorType, playSound, getPredicates(arguments)); } From 7613a02a3449f5d04a37e3ccb2475f280ab5611b Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 6 Aug 2025 12:22:20 +0800 Subject: [PATCH 02/57] =?UTF-8?q?refactor(furniture):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=B6=E5=85=B7=E5=87=BD=E6=95=B0=E7=94=9F=E6=88=90=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=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 --- .../context/function/ReplaceFurnitureFunction.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java index ab7e278ec..520863010 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java @@ -1,25 +1,14 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.furniture.AnchorType; -import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.Furniture; -import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; -import net.momirealms.craftengine.core.entity.player.InteractionHand; -import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.loot.LootTable; -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.ContextHolder; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; import java.util.List; From 245f31261e0da76d34cdcc1c6073f97f3eb92e56 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 6 Aug 2025 16:49:58 +0800 Subject: [PATCH 03/57] =?UTF-8?q?fix(gui):=20=E4=BF=AE=E5=A4=8D=E6=9F=90?= =?UTF-8?q?=E4=BA=9B=20GUI=20=E7=95=8C=E9=9D=A2=E5=AF=BC=E8=87=B4=E4=B8=A5?= =?UTF-8?q?=E9=87=8D=E5=8D=A1=E6=9C=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/gui/BukkitGuiManager.java | 7 +++++++ .../plugin/reflection/bukkit/CraftBukkitReflections.java | 4 ++++ .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 4 ++++ gradle.properties | 2 +- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index e6896e91f..26b31cebc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.gui; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.ComponentUtils; @@ -91,6 +92,9 @@ public class BukkitGuiManager implements GuiManager, Listener { @EventHandler(ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent event) { org.bukkit.inventory.Inventory inventory = event.getInventory(); + if (!CraftBukkitReflections.clazz$MinecraftInventory.isInstance(FastNMS.INSTANCE.method$CraftInventory$getInventory(inventory))) { + return; + } if (!(inventory.getHolder() instanceof CraftEngineInventoryHolder craftEngineInventoryHolder)) { return; } @@ -106,6 +110,9 @@ public class BukkitGuiManager implements GuiManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) public void onInventoryDrag(InventoryDragEvent event) { org.bukkit.inventory.Inventory inventory = event.getInventory(); + if (!CraftBukkitReflections.clazz$MinecraftInventory.isInstance(FastNMS.INSTANCE.method$CraftInventory$getInventory(inventory))) { + return; + } if (!(inventory.getHolder() instanceof CraftEngineInventoryHolder)) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java index fa15e41c7..a216443ec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java @@ -353,4 +353,8 @@ public final class CraftBukkitReflections { public static final Method method$Level$getCraftWorld = requireNonNull( ReflectionUtils.getMethod(CoreReflections.clazz$Level, clazz$CraftWorld) ); + + public static final Class clazz$MinecraftInventory = requireNonNull( + ReflectionUtils.getClazz(BukkitReflectionUtils.assembleCBClass("inventory.CraftInventoryCustom$MinecraftInventory")) + ); } 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 a2c501de6..64f58fa0c 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 @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineInventoryHolder; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; +import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MMobEffects; @@ -456,6 +457,9 @@ public class BukkitServerPlayer extends Player { private void updateGUI() { org.bukkit.inventory.Inventory top = !VersionHelper.isOrAbove1_21() ? LegacyInventoryUtils.getTopInventory(platformPlayer()) : platformPlayer().getOpenInventory().getTopInventory(); + if (!CraftBukkitReflections.clazz$MinecraftInventory.isInstance(FastNMS.INSTANCE.method$CraftInventory$getInventory(top))) { + return; + } if (top.getHolder() instanceof CraftEngineInventoryHolder holder) { holder.gui().onTimer(); } diff --git a/gradle.properties b/gradle.properties index cb6c151a3..49e177021 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.54 +nms_helper_version=1.0.55 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 81fd77d67bafd2c93507391f03639a73ce66bf68 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 7 Aug 2025 14:40:52 +0800 Subject: [PATCH 04/57] =?UTF-8?q?perf(bukkit):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=85=8D=E6=96=B9=E7=9B=B8=E5=85=B3=E5=8F=8D=E5=B0=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 77 +++---- .../bukkit/CraftBukkitReflections.java | 15 ++ .../reflection/minecraft/CoreReflections.java | 196 +++++++++++++++++- 3 files changed, 240 insertions(+), 48 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 373081c54..0fcba6c05 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item.recipe; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.papermc.paper.potion.PotionMix; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -144,11 +145,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager { .map(Optional::get) .toList(); if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); + CoreReflections.methodHandle$ShapedRecipe$placementInfoSetter.invokeExact(shapedRecipe, (Object) null); } List ingredients = getIngredientsFromShapedRecipe(shapedRecipe); modifyIngredients(ingredients, actualIngredients); - } catch (ReflectiveOperationException e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to inject shaped recipe", e); } } @@ -158,16 +159,16 @@ public class BukkitRecipeManager extends AbstractRecipeManager { List ingredients = new ArrayList<>(); try { if (VersionHelper.isOrAbove1_20_3()) { - Object pattern = CoreReflections.field$1_20_3$ShapedRecipe$pattern.get(recipe); + Object pattern = CoreReflections.methodHandle$1_20_3$ShapedRecipe$patternGetter.invokeExact(recipe); if (VersionHelper.isOrAbove1_21_2()) { - List> optionals = (List>) CoreReflections.field$ShapedRecipePattern$ingredients1_21_2.get(pattern); + List> optionals = (List>) CoreReflections.methodHandle$ShapedRecipePattern$ingredients1_21_2Getter.invokeExact(pattern); for (Optional optional : optionals) { optional.ifPresent(ingredients::add); } } else { - List objectList = (List) CoreReflections.field$ShapedRecipePattern$ingredients1_20_3.get(pattern); + List objectList = (List) CoreReflections.methodHandle$ShapedRecipePattern$ingredients1_20_3Getter.invokeExact(pattern); for (Object object : objectList) { - Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); + Object[] values = (Object[]) CoreReflections.methodHandle$Ingredient$valuesGetter.invokeExact(object); // is empty or not if (values.length != 0) { ingredients.add(object); @@ -175,15 +176,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } } } else { - List objectList = (List) CoreReflections.field$1_20_1$ShapedRecipe$recipeItems.get(recipe); + List objectList = (List) CoreReflections.methodHandle$1_20_1$ShapedRecipe$recipeItemsGetter.invokeExact(recipe); for (Object object : objectList) { - Object[] values = (Object[]) CoreReflections.field$Ingredient$values.get(object); + Object[] values = (Object[]) CoreReflections.methodHandle$Ingredient$valuesGetter.invokeExact(object); if (values.length != 0) { ingredients.add(object); } } } - } catch (ReflectiveOperationException e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to get ingredients from shaped recipe", e); } return ingredients; @@ -193,12 +194,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager { try { List> actualIngredients = recipe.ingredientsInUse(); if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); + CoreReflections.methodHandle$ShapelessRecipe$placementInfoSetter.invokeExact(shapelessRecipe, (Object) null); } @SuppressWarnings("unchecked") - List ingredients = (List) CoreReflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); + List ingredients = (List) CoreReflections.methodHandle$ShapelessRecipe$ingredientsGetter.invokeExact(shapelessRecipe); modifyIngredients(ingredients, actualIngredients); - } catch (ReflectiveOperationException e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to inject shapeless recipe", e); } } @@ -208,12 +209,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager { Ingredient actualIngredient = recipe.ingredient(); Object ingredient; if (VersionHelper.isOrAbove1_21_2()) { - ingredient = CoreReflections.field$SingleItemRecipe$input.get(cookingRecipe); + ingredient = CoreReflections.methodHandle$SingleItemRecipe$inputGetter.invokeExact(cookingRecipe); } else { - ingredient = CoreReflections.field$AbstractCookingRecipe$input.get(cookingRecipe); + ingredient = CoreReflections.methodHandle$AbstractCookingRecipe$inputGetter.invokeExact(cookingRecipe); } modifyIngredients(List.of(ingredient), List.of(actualIngredient)); - } catch (ReflectiveOperationException e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to inject cooking recipe", e); } } @@ -235,7 +236,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { return itemStacks; } - private static void modifyIngredients(List fakeIngredients, List> actualIngredients) throws ReflectiveOperationException { + private static void modifyIngredients(List fakeIngredients, List> actualIngredients) throws Throwable { if (fakeIngredients.size() != actualIngredients.size()) { throw new IllegalArgumentException("Ingredient count mismatch"); } @@ -244,15 +245,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager { Ingredient actualIngredient = actualIngredients.get(i); List items = getIngredientLooks(actualIngredient.items()); if (VersionHelper.isOrAbove1_21_4()) { - CoreReflections.field$Ingredient$itemStacks1_21_4.set(ingredient, new HashSet<>(items)); + CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Set) new ObjectOpenHashSet<>(items)); } else if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$Ingredient$itemStacks1_21_2.set(ingredient, items); + CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (List) items); } else { Object itemStackArray = Array.newInstance(CoreReflections.clazz$ItemStack, items.size()); for (int j = 0; j < items.size(); j++) { Array.set(itemStackArray, j, items.get(j)); } - CoreReflections.field$Ingredient$itemStacks1_20_1.set(ingredient, itemStackArray); + CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Object) itemStackArray); } MODIFIED_INGREDIENTS.add(ingredient); } @@ -308,9 +309,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager { if (!Config.enableRecipeSystem()) return; if (VersionHelper.isOrAbove1_21_2()) { try { - this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(minecraftRecipeManager()); - CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), null); - } catch (ReflectiveOperationException e) { + this.stolenFeatureFlagSet = CoreReflections.methodHandle$RecipeManager$featureflagsetGetter.invokeExact(minecraftRecipeManager()); + CoreReflections.methodHandle$RecipeManager$featureflagsetSetter.invokeExact(minecraftRecipeManager(), (Object) null); + } catch (Throwable e) { this.plugin.logger().warn("Failed to steal feature flag set", e); } } @@ -398,7 +399,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.replacedDatapackRecipes.clear(); try { this.lastDatapackRecipes = scanResources(); - } catch (ReflectiveOperationException e) { + } catch (Throwable e) { this.plugin.logger().warn("Failed to load datapack recipes", e); } } @@ -409,19 +410,19 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } @SuppressWarnings("unchecked") - private Map> scanResources() throws ReflectiveOperationException { - Object fileToIdConverter = CoreReflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isOrAbove1_21() ? "recipe" : "recipes"); + private Map> scanResources() throws Throwable { + Object fileToIdConverter = CoreReflections.methodHandle$FileToIdConverter$json.invokeExact((String) (VersionHelper.isOrAbove1_21() ? "recipe" : "recipes")); Object minecraftServer = FastNMS.INSTANCE.method$MinecraftServer$getServer(); - Object packRepository = CoreReflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); - List selected = (List) CoreReflections.field$PackRepository$selected.get(packRepository); + Object packRepository = CoreReflections.methodHandle$MinecraftServer$getPackRepository.invokeExact(minecraftServer); + List selected = (List) CoreReflections.methodHandle$PackRepository$selectedGetter.invokeExact(packRepository); List packResources = new ArrayList<>(); for (Object pack : selected) { - packResources.add(CoreReflections.method$Pack$open.invoke(pack)); + packResources.add(CoreReflections.methodHandle$Pack$open.invokeExact(pack)); } Map> recipes = new HashMap<>(); boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); - try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.constructor$MultiPackResourceManager.newInstance(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { - Map scannedResources = (Map) CoreReflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); + try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.methodHandle$MultiPackResourceManagerConstructor.invokeExact(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { + Map scannedResources = (Map) CoreReflections.methodHandle$FileToIdConverter$listMatchingResources.invokeExact(fileToIdConverter, resourceManager); for (Map.Entry entry : scannedResources.entrySet()) { Key id = extractKeyFromResourceLocation(entry.getKey().toString()); if (Config.disableAllVanillaRecipes()) { @@ -432,7 +433,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.recipesToUnregister.add(new Pair<>(id, false)); continue; } - Reader reader = (Reader) CoreReflections.method$Resource$openAsReader.invoke(entry.getValue()); + Reader reader = (Reader) CoreReflections.methodHandle$Resource$openAsReader.invokeExact(entry.getValue()); JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); Key serializerType = Key.of(jsonObject.get("type").getAsString()); RecipeSerializer> serializer = (RecipeSerializer>) BuiltInRegistries.RECIPE_SERIALIZER.getValue(serializerType); @@ -446,7 +447,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.plugin.logger().warn("Failed to load data pack recipe " + id + ". Json: " + jsonObject, e); } } - } catch (Exception e) { + } catch (Throwable e) { this.plugin.logger().warn("Unknown error occurred when loading data pack recipes", e); } return recipes; @@ -480,32 +481,32 @@ public class BukkitRecipeManager extends AbstractRecipeManager { try { // give flags back on 1.21.2+ if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) { - CoreReflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager(), this.stolenFeatureFlagSet); + CoreReflections.methodHandle$RecipeManager$featureflagsetSetter.invokeExact(minecraftRecipeManager(), (Object) this.stolenFeatureFlagSet); this.stolenFeatureFlagSet = null; } // refresh recipes if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager()); + CoreReflections.methodHandle$RecipeManager$finalizeRecipeLoading.invokeExact(minecraftRecipeManager()); } // send to players - CoreReflections.method$DedicatedPlayerList$reloadRecipes.invoke(CraftBukkitReflections.field$CraftServer$playerList.get(Bukkit.getServer())); + CoreReflections.methodHandle$DedicatedPlayerList$reloadRecipes.invokeExact(CraftBukkitReflections.methodHandle$CraftServer$playerListGetter.invokeExact(Bukkit.getServer())); // now we need to remove the fake `exact` choices if (VersionHelper.isOrAbove1_21_4()) { for (Object ingredient : MODIFIED_INGREDIENTS) { - CoreReflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); + CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Set) null); } } else if (VersionHelper.isOrAbove1_21_2()) { for (Object ingredient : MODIFIED_INGREDIENTS) { - CoreReflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); + CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (List) null); } } // clear cache MODIFIED_INGREDIENTS.clear(); - } catch (Exception e) { + } catch (Throwable e) { this.plugin.logger().warn("Failed to run delayed recipe tasks", e); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java index a216443ec..7d09bd51f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java @@ -1,10 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.bukkit; +import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.NamespacedKey; +import org.bukkit.Server; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.entity.HumanEntity; @@ -12,6 +14,8 @@ import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -201,6 +205,17 @@ public final class CraftBukkitReflections { ReflectionUtils.getDeclaredField(clazz$CraftServer, CoreReflections.clazz$DedicatedPlayerList, 0) ); + public static final MethodHandle methodHandle$CraftServer$playerListGetter; + + static { + try { + methodHandle$CraftServer$playerListGetter = ReflectionUtils.unreflectGetter(field$CraftServer$playerList) + .asType(MethodType.methodType(Object.class, Server.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize methodHandle$CraftServer$playerList", e); + } + } + public static final Class clazz$CraftInventoryCrafting = requireNonNull( ReflectionUtils.getClazz(BukkitReflectionUtils.assembleCBClass("inventory.CraftInventoryCrafting")) ); 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 0d494798a..bff6a601b 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 @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import java.io.BufferedReader; +import java.io.Reader; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; @@ -97,6 +98,17 @@ public final class CoreReflections { public static final Method method$FileToIdConverter$json = requireNonNull( ReflectionUtils.getStaticMethod(clazz$FileToIdConverter, clazz$FileToIdConverter, String.class) ); + + public static final MethodHandle methodHandle$FileToIdConverter$json; + + static { + try { + methodHandle$FileToIdConverter$json = ReflectionUtils.unreflectMethod(method$FileToIdConverter$json) + .asType(MethodType.methodType(Object.class, String.class)); + } catch (Throwable t) { + throw new ReflectionInitException("Failed to initialize methodHandle$FileToIdConverter$json", t); + } + } public static final Class clazz$RegistryOps = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -1900,17 +1912,42 @@ public final class CoreReflections { ) ); - // 1.20.1-1.21.1 - public static final Field field$Ingredient$itemStacks1_20_1 = - ReflectionUtils.getDeclaredField(clazz$Ingredient, clazz$ItemStack.arrayType(), 0); + public static final Field field$Ingredient$itemStacks = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$Ingredient, + VersionHelper.isOrAbove1_21_4() ? Set.class : VersionHelper.isOrAbove1_21_2() ? List.class : clazz$ItemStack.arrayType(), + VersionHelper.isOrAbove1_21_4() ? 0 : VersionHelper.isOrAbove1_21_2() ? 1 : 0 + ) + ); - // 1.21.2-1.21.3 - public static final Field field$Ingredient$itemStacks1_21_2 = - ReflectionUtils.getDeclaredField(clazz$Ingredient, List.class, 1); + public static final MethodHandle methodHandle$RecipeManager$finalizeRecipeLoading; + public static final MethodHandle methodHandle$RecipeManager$featureflagsetGetter; + public static final MethodHandle methodHandle$RecipeManager$featureflagsetSetter; + public static final MethodHandle methodHandle$Ingredient$itemStacksSetter; - // 1.21.4 paper - public static final Field field$Ingredient$itemStacks1_21_4 = - ReflectionUtils.getDeclaredField(clazz$Ingredient, Set.class, 0); + static { + try { + if (method$RecipeManager$finalizeRecipeLoading != null) { + methodHandle$RecipeManager$finalizeRecipeLoading = ReflectionUtils.unreflectMethod(method$RecipeManager$finalizeRecipeLoading) + .asType(MethodType.methodType(void.class, Object.class)); + } else { + methodHandle$RecipeManager$finalizeRecipeLoading = null; + } + if (field$RecipeManager$featureflagset != null) { + methodHandle$RecipeManager$featureflagsetGetter = ReflectionUtils.unreflectGetter(field$RecipeManager$featureflagset) + .asType(MethodType.methodType(Object.class, Object.class)); + methodHandle$RecipeManager$featureflagsetSetter = ReflectionUtils.unreflectSetter(field$RecipeManager$featureflagset) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$RecipeManager$featureflagsetGetter = null; + methodHandle$RecipeManager$featureflagsetSetter = null; + } + methodHandle$Ingredient$itemStacksSetter = ReflectionUtils.unreflectSetter(field$Ingredient$itemStacks) + .asType(MethodType.methodType(void.class, Object.class, VersionHelper.isOrAbove1_21_4() ? Set.class : VersionHelper.isOrAbove1_21_2() ? List.class : Object.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize CoreReflections", e); + } + } // Since 1.21.2, exact has been removed public static final Field field$Ingredient$exact = @@ -1928,7 +1965,7 @@ public final class CoreReflections { ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("world.item.crafting.ShapedRecipePattern")); // 1.20.1-1.20.2 - public static final Field field$1_20_1$ShapedRecipe$recipeItems= + public static final Field field$1_20_1$ShapedRecipe$recipeItems = ReflectionUtils.getDeclaredField(clazz$ShapedRecipe, clazz$NonNullList, 0); // 1.20.3+ @@ -1992,6 +2029,70 @@ public final class CoreReflections { Optional.ofNullable(ReflectionUtils.getDeclaredField(clazz$ShapelessRecipe, List.class, 0)) .orElse(ReflectionUtils.getDeclaredField(clazz$ShapelessRecipe, clazz$NonNullList, 0)); + public static final MethodHandle methodHandle$1_20_1$ShapedRecipe$recipeItemsGetter; + public static final MethodHandle methodHandle$1_20_3$ShapedRecipe$patternGetter; + public static final MethodHandle methodHandle$ShapedRecipePattern$ingredients1_20_3Getter; + public static final MethodHandle methodHandle$ShapedRecipePattern$ingredients1_21_2Getter; + public static final MethodHandle methodHandle$Ingredient$valuesGetter; + public static final MethodHandle methodHandle$ShapelessRecipe$placementInfoSetter; + public static final MethodHandle methodHandle$ShapedRecipe$placementInfoSetter; + public static final MethodHandle methodHandle$ShapelessRecipe$ingredientsGetter; + + static { + try { + if (field$1_20_1$ShapedRecipe$recipeItems != null) { + methodHandle$1_20_1$ShapedRecipe$recipeItemsGetter = ReflectionUtils.unreflectGetter(field$1_20_1$ShapedRecipe$recipeItems) + .asType(MethodType.methodType(List.class, Object.class)); + } else { + methodHandle$1_20_1$ShapedRecipe$recipeItemsGetter = null; + } + if (field$1_20_3$ShapedRecipe$pattern != null) { + methodHandle$1_20_3$ShapedRecipe$patternGetter = ReflectionUtils.unreflectGetter(field$1_20_3$ShapedRecipe$pattern) + .asType(MethodType.methodType(Object.class, Object.class)); + } else { + methodHandle$1_20_3$ShapedRecipe$patternGetter = null; + } + if (field$ShapedRecipePattern$ingredients1_20_3 != null) { + methodHandle$ShapedRecipePattern$ingredients1_20_3Getter = ReflectionUtils.unreflectGetter(field$ShapedRecipePattern$ingredients1_20_3) + .asType(MethodType.methodType(List.class, Object.class)); + } else { + methodHandle$ShapedRecipePattern$ingredients1_20_3Getter = null; + } + if (field$ShapedRecipePattern$ingredients1_21_2 != null) { + methodHandle$ShapedRecipePattern$ingredients1_21_2Getter = ReflectionUtils.unreflectGetter(field$ShapedRecipePattern$ingredients1_21_2) + .asType(MethodType.methodType(List.class, Object.class)); + } else { + methodHandle$ShapedRecipePattern$ingredients1_21_2Getter = null; + } + if (field$Ingredient$values != null) { + methodHandle$Ingredient$valuesGetter = ReflectionUtils.unreflectGetter(field$Ingredient$values) + .asType(MethodType.methodType(Object[].class, Object.class)); + } else { + methodHandle$Ingredient$valuesGetter = null; + } + if (field$ShapelessRecipe$placementInfo != null) { + methodHandle$ShapelessRecipe$placementInfoSetter = ReflectionUtils.unreflectSetter(field$ShapelessRecipe$placementInfo) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ShapelessRecipe$placementInfoSetter = null; + } + if (field$ShapedRecipe$placementInfo != null) { + methodHandle$ShapedRecipe$placementInfoSetter = ReflectionUtils.unreflectSetter(field$ShapedRecipe$placementInfo) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ShapedRecipe$placementInfoSetter = null; + } + if (field$ShapelessRecipe$ingredients != null) { + methodHandle$ShapelessRecipe$ingredientsGetter = ReflectionUtils.unreflectGetter(field$ShapelessRecipe$ingredients) + .asType(MethodType.methodType(List.class, Object.class)); + } else { + methodHandle$ShapelessRecipe$ingredientsGetter = null; + } + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize CoreReflections", e); + } + } + // require ResourceLocation for 1.20.1-1.21.1 // require ResourceKey for 1.21.2+ public static final Method method$RecipeManager$byKey; @@ -2093,6 +2194,28 @@ public final class CoreReflections { .map(it -> ReflectionUtils.getDeclaredField(it, clazz$Ingredient, 0)) .orElse(null); + public static final MethodHandle methodHandle$AbstractCookingRecipe$inputGetter; + public static final MethodHandle methodHandle$SingleItemRecipe$inputGetter; + + static { + try { + if (field$AbstractCookingRecipe$input != null) { + methodHandle$AbstractCookingRecipe$inputGetter = ReflectionUtils.unreflectGetter(field$AbstractCookingRecipe$input) + .asType(MethodType.methodType(Object.class, Object.class)); + } else { + methodHandle$AbstractCookingRecipe$inputGetter = null; + } + if (field$SingleItemRecipe$input != null) { + methodHandle$SingleItemRecipe$inputGetter = ReflectionUtils.unreflectGetter(field$SingleItemRecipe$input) + .asType(MethodType.methodType(Object.class, Object.class)); + } else { + methodHandle$SingleItemRecipe$inputGetter = null; + } + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize methodHandle$SingleItemRecipe$inputGetter", e); + } + } + public static final Field field$AbstractFurnaceBlockEntity$quickCheck = requireNonNull( ReflectionUtils.getDeclaredField(clazz$AbstractFurnaceBlockEntity, clazz$RecipeManager$CachedCheck, 0) ); @@ -3019,6 +3142,17 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$Resource, BufferedReader.class) ); + public static final MethodHandle methodHandle$Resource$openAsReader; + + static { + try { + methodHandle$Resource$openAsReader = ReflectionUtils.unreflectMethod(method$Resource$openAsReader) + .asType(MethodType.methodType(Reader.class, Object.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to init methodHandle$Resource$openAsReader", e); + } + } + public static final Class clazz$MultiPackResourceManager = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "server.packs.resources.ResourceManager", @@ -3063,6 +3197,20 @@ public final class CoreReflections { ReflectionUtils.getInstanceDeclaredField(clazz$PackRepository, List.class, 0) ); + public static final MethodHandle methodHandle$MinecraftServer$getPackRepository; + public static final MethodHandle methodHandle$PackRepository$selectedGetter; + + static { + try { + methodHandle$MinecraftServer$getPackRepository = ReflectionUtils.unreflectMethod(method$MinecraftServer$getPackRepository) + .asType(MethodType.methodType(Object.class, Object.class)); + methodHandle$PackRepository$selectedGetter = ReflectionUtils.unreflectGetter(field$PackRepository$selected) + .asType(MethodType.methodType(List.class, Object.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize reflection for methodHandle$MinecraftServer$getPackRepository", e); + } + } + public static final Class clazz$Pack = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "server.packs.repository.ResourcePackLoader", @@ -3109,6 +3257,23 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$DedicatedPlayerList, new String[] {"reloadRecipeData", "reloadRecipes"}) ); + public static final MethodHandle methodHandle$DedicatedPlayerList$reloadRecipes; + public static final MethodHandle methodHandle$Pack$open; + public static final MethodHandle methodHandle$MultiPackResourceManagerConstructor; + + static { + try { + methodHandle$DedicatedPlayerList$reloadRecipes = ReflectionUtils.unreflectMethod(method$DedicatedPlayerList$reloadRecipes) + .asType(MethodType.methodType(void.class, Object.class)); + methodHandle$Pack$open = ReflectionUtils.unreflectMethod(method$Pack$open) + .asType(MethodType.methodType(Object.class, Object.class)); + methodHandle$MultiPackResourceManagerConstructor = ReflectionUtils.unreflectConstructor(constructor$MultiPackResourceManager) + .asType(MethodType.methodType(AutoCloseable.class, Object.class, List.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to init methodHandle$DedicatedPlayerList$reloadRecipes", e); + } + } + public static final Method method$ServerChunkCache$getGenerator = requireNonNull( ReflectionUtils.getMethod(clazz$ServerChunkCache, clazz$ChunkGenerator) ); @@ -3315,6 +3480,17 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$FileToIdConverter, Map.class, new String[]{"listMatchingResources", "a"}, clazz$ResourceManager) ); + public static final MethodHandle methodHandle$FileToIdConverter$listMatchingResources; + + static { + try { + methodHandle$FileToIdConverter$listMatchingResources = ReflectionUtils.unreflectMethod(method$FileToIdConverter$listMatchingResources) + .asType(MethodType.methodType(Map.class, Object.class, AutoCloseable.class)); + } catch (Exception e) { + throw new ReflectionInitException("Failed to initialize methodHandle$FileToIdConverter$listMatchingResources", e); + } + } + public static final Method method$RegistryOps$create = requireNonNull( ReflectionUtils.getStaticMethod(clazz$RegistryOps, clazz$RegistryOps, DynamicOps.class, clazz$HolderLookup$Provider) ); From b1187d19ca135db70d96f2b9e98e643d52f8f948 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 7 Aug 2025 21:39:30 +0800 Subject: [PATCH 05/57] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D=20Dropbox?= =?UTF-8?q?=20=E7=BC=93=E5=AD=98=E6=96=87=E4=BB=B6=E5=86=99=E5=85=A5?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/core/pack/host/impl/DropboxHost.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java index 8f6cf2b92..beab2350a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java @@ -73,7 +73,7 @@ public class DropboxHost implements ResourcePackHost { cache.addProperty("expires_at", this.expiresAt); Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("dropbox.json"); try { - Files.createDirectories(cachePath); + Files.createDirectories(cachePath.getParent()); Files.writeString( cachePath, GsonHelper.get().toJson(cache), From 307724077aa17359c4453e358698d7ef118d752c Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 12:33:26 +0800 Subject: [PATCH 06/57] =?UTF-8?q?=E9=87=8D=E5=86=99Skript=E5=A4=84?= =?UTF-8?q?=E7=90=86Custom=20Item=E7=9A=84=E7=9B=B8=E5=85=B3=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skript/condition/CondIsCustomItem.java | 54 +++++++++---- .../skript/expression/ExprCustomItem.java | 45 ++++++++--- .../expression/ExprItemCustomItemID.java | 80 ++++++++++++------- 3 files changed, 122 insertions(+), 57 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomItem.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomItem.java index b293e710f..bf4c52fe8 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomItem.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomItem.java @@ -1,41 +1,65 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.condition; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.util.slot.Slot; import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +@Name("Is CraftEngine Item") +@Description({"Checks if the Item is CraftEngine item."}) +@Since("1.0") public class CondIsCustomItem extends Condition { public static void register() { Skript.registerCondition(CondIsCustomItem.class, - "%itemstacks% (is|are) custom item(s)", - "%itemstacks% (is|are)(n't| not) custom item(s)"); + "%itemstack/itemtype/slot% (is [a[n]]|are) (custom|ce|craft-engine) item[s]", + "%itemstack/itemtype/slot% (isn't|is not|aren't|are not) [a[n]] (custom|ce|craft-engine) item[s]" + ); } - private Expression items; - - @Override - public boolean check(Event event) { - return items.check(event, CraftEngineItems::isCustomItem, isNegated()); - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, items, "itemstack"); - } + private Expression item; @SuppressWarnings("unchecked") @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - items = (Expression) expressions[0]; - setNegated(matchedPattern > 1); + item = expressions[0]; + setNegated(matchedPattern == 1); return true; } + + @Override + public boolean check(Event event) { + Object single = item.getSingle(event); + + ItemStack checkItemStack = null; + if (single instanceof ItemType itemType) { + checkItemStack = itemType.getTypes().getFirst().getStack(); + } else if (single instanceof ItemStack itemStack) { + checkItemStack = itemStack; + } else if (single instanceof Slot slot) { + checkItemStack = slot.getItem(); + } + + if (checkItemStack == null) return isNegated() ? true : false; + + boolean exists = CraftEngineItems.isCustomItem(checkItemStack); + if (!exists) return isNegated() ? true : false; + return isNegated() ? false : true; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return PropertyCondition.toString(this, PropertyCondition.PropertyType.BE, event, debug, item, "itemtypes"); + } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java index aacfe01ff..6ad45ad4c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java @@ -1,6 +1,10 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.expression; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser; @@ -14,29 +18,44 @@ import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -public class ExprCustomItem extends SimpleExpression { +import java.util.ArrayList; +import java.util.List; + +@Name("CraftEngine Item") +@Description({"Get CraftEngine items."}) +@Since("1.0") +public class ExprCustomItem extends SimpleExpression { public static void register() { - Skript.registerExpression(ExprCustomItem.class, ItemStack.class, ExpressionType.SIMPLE, "[(the|a)] custom item [with id] %string%"); + Skript.registerExpression(ExprCustomItem.class, ItemType.class, ExpressionType.SIMPLE, "[(the|a)] (custom|ce|craft-engine) item [with [namespace] id] %strings%"); } - private Expression itemId; + private Expression itemIds; @Override @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - itemId = (Expression) exprs[0]; + itemIds = exprs[0]; return true; } @Override @Nullable - protected ItemStack[] get(Event e) { - String itemId = this.itemId.getSingle(e); - if (itemId == null) - return null; - CustomItem customItem = CraftEngineItems.byId(Key.of(itemId)); - return customItem == null ? null : new ItemStack[] {customItem.buildItemStack(ItemBuildContext.EMPTY)}; + protected ItemType[] get(Event event) { + Object[] objects = itemIds.getArray(event); + List items = new ArrayList<>(); + + for (Object object : objects) { + if (object instanceof String string) { + CustomItem customItem = CraftEngineItems.byId(Key.of(string)); + if (customItem != null) { + ItemType itemType = new ItemType(customItem.buildItemStack(ItemBuildContext.EMPTY)); + items.add(itemType); + } + } + } + + return items.toArray(new ItemType[0]); } @Override @@ -45,12 +64,12 @@ public class ExprCustomItem extends SimpleExpression { } @Override - public Class getReturnType() { - return ItemStack.class; + public Class getReturnType() { + return ItemType.class; } @Override public String toString(@Nullable Event e, boolean debug) { - return "the custom item with id " + itemId.toString(e, debug); + return "craft-engine item with id " + itemIds.toString(e, debug); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprItemCustomItemID.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprItemCustomItemID.java index ce92f9857..8e13df907 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprItemCustomItemID.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprItemCustomItemID.java @@ -1,12 +1,18 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.expression; +import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.classes.Changer; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.util.coll.CollectionUtils; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; @@ -14,27 +20,52 @@ import org.jetbrains.annotations.Nullable; import java.util.Optional; -public class ExprItemCustomItemID extends SimplePropertyExpression { +@Name("CraftEngine Item ID") +@Description({"Get CraftEngine item id."}) +@Since("1.0") +public class ExprItemCustomItemID extends SimpleExpression { public static void register() { - register(ExprItemCustomItemID.class, String.class, "custom item id", "itemstacks/itemtypes"); + Skript.registerExpression(ExprItemCustomItemID.class, String.class, ExpressionType.PROPERTY, + "(custom|ce|craft-engine) item [namespace] id of %itemstack/itemtype/slot%", + "%itemstack/itemtype/slot%'[s] (custom|ce|craft-engine) item [namespace] id" + ); + } + + private Expression itemStackExpr; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + itemStackExpr = exprs[0]; + return true; } @Override - public @Nullable String convert(Object object) { - if (object instanceof ItemStack itemStack) - return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null); - if (object instanceof ItemType itemType) { - ItemStack itemStack = new ItemStack(itemType.getMaterial()); - itemStack.setItemMeta(itemType.getItemMeta()); - return Optional.ofNullable(CraftEngineItems.byItemStack(itemStack)).map(it -> it.id().toString()).orElse(null); + protected String[] get(Event event) { + Object single = itemStackExpr.getSingle(event); + + String result = null; + if (single instanceof ItemStack itemStack) { + result = Optional.of(itemStack).map(this::getCraftEngineItemId).orElse(null); + } else if (single instanceof ItemType itemType) { + result = Optional.ofNullable(itemType.getTypes().getFirst().getStack()).map(this::getCraftEngineItemId).orElse(null); + } else if (single instanceof Slot slot) { + result = Optional.ofNullable(slot.getItem()).map(this::getCraftEngineItemId).orElse(null); } - return null; + + return new String[] {result}; + } + + + private String getCraftEngineItemId(ItemStack itemStack) { + return Optional.ofNullable(CraftEngineItems.getCustomItemId(itemStack)) + .map(Key::asString) + .orElse(null); } @Override - protected String getPropertyName() { - return "custom item id"; + public boolean isSingle() { + return itemStackExpr.isSingle(); } @Override @@ -42,23 +73,14 @@ public class ExprItemCustomItemID extends SimplePropertyExpression[] acceptChange(Changer.ChangeMode mode) { - return CollectionUtils.array(String.class); + return null; } @Override - public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { - Key id = Key.of((String) delta[0]); - for (Object item : getExpr().getArray(e)) { - if (item instanceof ItemStack itemStack) { - Item item1 = BukkitItemManager.instance().wrap(itemStack); - Item item2 = BukkitItemManager.instance().createWrappedItem(id, null); - item1.merge(item2); - } else if (item instanceof ItemType itemType) { - Item item2 = BukkitItemManager.instance().createWrappedItem(id, null); - itemType.setItemMeta(item2.getItem().getItemMeta()); - } - } + public String toString(@Nullable Event event, boolean debug) { + return "craft-engine item ID of " + itemStackExpr.toString(event, debug); } } From afa328f8598a610d7cf984e9af272d63fcc7fa82 Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 13:24:31 +0800 Subject: [PATCH 07/57] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BA=8B=E4=BB=B6,=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0ce=E5=AD=97=E6=AE=B5,=20=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E5=92=8Csk=E6=9C=AC=E8=BA=AB=E7=9A=84=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/skript/SkriptHook.java | 4 ++ .../CondIsCraftEngineHasBeenLoad.java | 45 ++++++++++++++++ .../skript/event/EvtCraftEngineReload.java | 54 +++++++++++++++++++ .../skript/event/EvtCustomBlock.java | 10 +++- .../skript/event/EvtCustomClick.java | 10 +++- .../skript/event/EvtCustomFurniture.java | 10 +++- 6 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/SkriptHook.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/SkriptHook.java index 3e010e30c..bee455f92 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/SkriptHook.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/SkriptHook.java @@ -1,12 +1,14 @@ package net.momirealms.craftengine.bukkit.compatibility.skript; import net.momirealms.craftengine.bukkit.compatibility.skript.clazz.CraftEngineClasses; +import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCraftEngineHasBeenLoad; import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomBlock; import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsCustomItem; import net.momirealms.craftengine.bukkit.compatibility.skript.condition.CondIsFurniture; import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceCustomBlock; import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffPlaceFurniture; import net.momirealms.craftengine.bukkit.compatibility.skript.effect.EffRemoveFurniture; +import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCraftEngineReload; import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomBlock; import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomClick; import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCustomFurniture; @@ -16,9 +18,11 @@ public class SkriptHook { public static void register() { CraftEngineClasses.register(); + EvtCraftEngineReload.register(); EvtCustomBlock.register(); EvtCustomFurniture.register(); EvtCustomClick.register(); + CondIsCraftEngineHasBeenLoad.register(); CondIsCustomBlock.register(); CondIsFurniture.register(); CondIsCustomItem.register(); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java new file mode 100644 index 000000000..39483f088 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.bukkit.compatibility.skript.condition; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import net.momirealms.craftengine.bukkit.compatibility.skript.event.EvtCraftEngineReload; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("CraftEngine has been load") +@Description({"Checks CraftEngine has been load."}) +@Since("1.0") +public class CondIsCraftEngineHasBeenLoad extends Condition { + + public static void register() { + Skript.registerCondition(CondIsCraftEngineHasBeenLoad.class, + "(ce|craft-engine) has been load[ed]", + "(ce|craft-engine) has not been load[ed] [yet]" + ); + } + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + setNegated(matchedPattern == 1); + return true; + } + + @Override + public boolean check(Event event) { + boolean beenLoad = EvtCraftEngineReload.hasBeenLoad(); + return isNegated() ? !beenLoad : beenLoad; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "craft-engine has " + (isNegated() ? "not " : "") + "been loaded"; + } + + +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java new file mode 100644 index 000000000..940c615f5 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java @@ -0,0 +1,54 @@ +package net.momirealms.craftengine.bukkit.compatibility.skript.event; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptEvent; +import ch.njol.skript.lang.SkriptParser; +import net.momirealms.craftengine.bukkit.api.event.CraftEngineReloadEvent; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("On CraftEngine Reload") +@Description({"Fires when CraftEngine reload"}) +@Since("1.0") +public class EvtCraftEngineReload extends SkriptEvent { + + public static void register() { + Skript.registerEvent("CraftEngine Loaded", EvtCraftEngineReload.class, CraftEngineReloadEvent.class, "(ce|craft(engine|-engine)) [first] (load[ed]|reload)") + .description("Called when Craft-Engine resource loaded."); + } + + private boolean onlyCheckFirstCall; + private static boolean hasBeenCalled = false; + + @Override + public boolean init(Literal[] args, int matchedPattern, SkriptParser.ParseResult parser) { + // 检查是否包含 "first" 关键词 + String expr = parser.expr; + this.onlyCheckFirstCall = expr.contains("first"); + return true; + } + + @Override + public boolean check(Event event) { + if (event instanceof CraftEngineReloadEvent reloadEvent) return false; + if (onlyCheckFirstCall) { + if (hasBeenCalled) return false; // 如果 hasBeenCalled 已经为 true,代表已经调用过了, 故返回 false。 + hasBeenCalled = true; + return true; + } + return true; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return onlyCheckFirstCall ? "craftengine first load" : "craftengine reload"; + } + + public static boolean hasBeenLoad() { + return hasBeenCalled; + } +} \ No newline at end of file diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java index e5510c23d..d46dc3ca4 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java @@ -1,6 +1,9 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.event; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; @@ -16,12 +19,15 @@ import org.jetbrains.annotations.Nullable; import java.util.Arrays; @SuppressWarnings({"unchecked"}) +@Name("On Custom Block Place And Break") +@Description({"Fires when a Custom block gets place and broken"}) +@Since("1.0") public class EvtCustomBlock extends SkriptEvent { public static void register() { - Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "(break[ing]|1¦min(e|ing)) [[of] %-unsafeblockstatematchers%]") + Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "(break[ing]|1¦min(e|ing)) of (custom|ce|craft-engine) block [[of] %-unsafeblockstatematchers%]") .description("Called when a custom block is broken by a player. If you use 'on mine', only events where the broken block dropped something will call the trigger."); - Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-unsafeblockstatematchers%]") + Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) of (custom|ce|craft-engine) block [[of] %-unsafeblockstatematchers%]") .description("Called when a player places a custom block."); } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java index 8c37c2a04..c5c367cf8 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java @@ -3,6 +3,9 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.event; import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.bukkitutil.ClickEventTracker; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; @@ -17,6 +20,9 @@ import org.jetbrains.annotations.Nullable; import java.util.function.Predicate; +@Name("On Click with Custom Item") +@Description({"Fires when click a custom item"}) +@Since("1.0") public class EvtCustomClick extends SkriptEvent { private final static int RIGHT = 1, LEFT = 2, ANY = RIGHT | LEFT; @@ -25,8 +31,8 @@ public class EvtCustomClick extends SkriptEvent { @SuppressWarnings("unchecked") public static void register() { Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class}, - "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", - "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%"); + "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (custom|ce|craft-engine) item[s] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", + "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (custom|ce|craft-engine) item[s] (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%"); } private @Nullable Literal type; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java index 081b72f85..c254c999c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java @@ -1,6 +1,9 @@ package net.momirealms.craftengine.bukkit.compatibility.skript.event; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; @@ -12,12 +15,15 @@ import org.jetbrains.annotations.Nullable; import java.util.Arrays; @SuppressWarnings({"unchecked"}) +@Name("On Custom Furniture Place And Break") +@Description({"Fires when a Custom furniture gets place and broken"}) +@Since("1.0") public class EvtCustomFurniture extends SkriptEvent { public static void register() { - Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) [[of] %-strings%]") + Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) of (custom|ce|craft-engine) furniture[s] [[of] %-strings%]") .description("Called when a furniture is broken by a player."); - Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) [[of] %-strings%]") + Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) of (custom|ce|craft-engine) furniture[s] [[of] %-strings%]") .description("Called when a player places a furniture."); } From db293941ebc07286013c9237b8e44d2a88c566ce Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 13:25:12 +0800 Subject: [PATCH 08/57] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5,=20=E6=B7=BB=E5=8A=A0ce=E5=AD=97=E6=AE=B5,?= =?UTF-8?q?=20=E9=81=BF=E5=85=8D=E5=92=8Csk=E6=9C=AC=E8=BA=AB=E7=9A=84?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/compatibility/skript/effect/EffPlaceCustomBlock.java | 2 +- .../bukkit/compatibility/skript/effect/EffPlaceFurniture.java | 2 +- .../bukkit/compatibility/skript/effect/EffRemoveFurniture.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceCustomBlock.java index 70f6df975..e330f9989 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceCustomBlock.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; public class EffPlaceCustomBlock extends Effect { public static void register() { - Skript.registerEffect(EffPlaceCustomBlock.class, "place custom block %customblockstates% [%directions% %locations%]"); + Skript.registerEffect(EffPlaceCustomBlock.class, "place (custom|ce|craft-engine) block %customblockstates% [at] [%directions% %locations%]"); } private Expression blocks; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java index 5972298e8..7b5e9284e 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; public class EffPlaceFurniture extends Effect { public static void register() { - Skript.registerEffect(EffPlaceFurniture.class, "place furniture %strings% [%directions% %locations%]"); + Skript.registerEffect(EffPlaceFurniture.class, "place (custom|ce|craft-engine) furniture %strings% [at] [%directions% %locations%]"); } private Expression furniture; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java index 5996a8ae7..224d7b5a9 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; public class EffRemoveFurniture extends Effect { public static void register() { - Skript.registerEffect(EffRemoveFurniture.class, "remove furniture %entities%"); + Skript.registerEffect(EffRemoveFurniture.class, "remove (custom|ce|craft-engine) furniture %entities%"); } private Expression entities; From b7d581870318cc6ee017ac08f8929e017c86f1cc Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 13:25:21 +0800 Subject: [PATCH 09/57] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5,=20=E6=B7=BB=E5=8A=A0ce=E5=AD=97=E6=AE=B5,?= =?UTF-8?q?=20=E9=81=BF=E5=85=8D=E5=92=8Csk=E6=9C=AC=E8=BA=AB=E7=9A=84?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/skript/condition/CondIsCustomBlock.java | 4 ++-- .../compatibility/skript/condition/CondIsFurniture.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java index 1f40970fa..3fc6fed21 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java @@ -15,8 +15,8 @@ public class CondIsCustomBlock extends Condition { public static void register() { Skript.registerCondition(CondIsCustomBlock.class, - "%blocks% (is|are) custom block(s)", - "%blocks% (is|are)(n't| not) custom block(s)"); + "%blocks% (is|are) (custom|ce|craft-engine) block(s)", + "%blocks% (is|are)(n't| not) (custom|ce|craft-engine) block(s)"); } private Expression blocks; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java index 00f3f7ad6..265cb9e00 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java @@ -15,8 +15,8 @@ public class CondIsFurniture extends Condition { public static void register() { Skript.registerCondition(CondIsFurniture.class, - "%entities% (is|are) furniture", - "%entities% (is|are)(n't| not) furniture"); + "%entities% (is|are) (custom|ce|craft-engine) furniture", + "%entities% (is|are)(n't| not) (custom|ce|craft-engine) furniture"); } private Expression entities; From 44f8c889463a03c618070aa708dbb0fe73a32ca3 Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 13:47:00 +0800 Subject: [PATCH 10/57] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E8=AF=AD=E5=8F=A5,=20=E6=B7=BB=E5=8A=A0ce=E5=AD=97?= =?UTF-8?q?=E6=AE=B5,=20=E9=81=BF=E5=85=8D=E5=92=8Csk=E6=9C=AC=E8=BA=AB?= =?UTF-8?q?=E7=9A=84=E8=AF=AD=E6=B3=95=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/skript/expression/ExprBlockCustomBlockID.java | 2 +- .../skript/expression/ExprBlockCustomBlockState.java | 2 +- .../compatibility/skript/expression/ExprEntityFurnitureID.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockID.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockID.java index db116d731..1c2a0d692 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockID.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockID.java @@ -13,7 +13,7 @@ import java.util.Optional; public class ExprBlockCustomBlockID extends SimplePropertyExpression { public static void register() { - register(ExprBlockCustomBlockID.class, String.class, "custom block id", "blocks/blockdata/customblockstates"); + register(ExprBlockCustomBlockID.class, String.class, "(custom|ce|craft-engine) block [namespace] id", "blocks/blockdata/customblockstates"); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockState.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockState.java index 04874c3c3..bb0f1da29 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockState.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprBlockCustomBlockState.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; public class ExprBlockCustomBlockState extends SimplePropertyExpression { public static void register() { - register(ExprBlockCustomBlockState.class, ImmutableBlockState.class, "custom block[ ]state", "blocks/blockdata"); + register(ExprBlockCustomBlockState.class, ImmutableBlockState.class, "(custom|ce|craft-engine) block[ ]state", "blocks/blockdata"); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java index bd3d4b988..864dd7ebd 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java @@ -10,7 +10,7 @@ import java.util.Optional; public class ExprEntityFurnitureID extends SimplePropertyExpression { public static void register() { - register(ExprEntityFurnitureID.class, String.class, "furniture id", "entities"); + register(ExprEntityFurnitureID.class, String.class, "(custom|ce|craft-engine) furniture [namespace] id", "entities"); } @Override From 82e4e3ddd59b91a5db3d6d5ac7cf50a2a20d1111 Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 14:28:01 +0800 Subject: [PATCH 11/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8DEvtCraftEngineReload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/skript/event/EvtCraftEngineReload.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java index 940c615f5..ec1b1005a 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCraftEngineReload.java @@ -34,12 +34,15 @@ public class EvtCraftEngineReload extends SkriptEvent { @Override public boolean check(Event event) { - if (event instanceof CraftEngineReloadEvent reloadEvent) return false; + if (!(event instanceof CraftEngineReloadEvent reloadEvent)) { + return false; + } if (onlyCheckFirstCall) { if (hasBeenCalled) return false; // 如果 hasBeenCalled 已经为 true,代表已经调用过了, 故返回 false。 hasBeenCalled = true; return true; } + hasBeenCalled = true; return true; } From 9b6e7c5d7d454f030788b92ac44b65c168cec1cc Mon Sep 17 00:00:00 2001 From: Catnies Date: Fri, 8 Aug 2025 14:57:54 +0800 Subject: [PATCH 12/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8DEvtCustomFurniture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/compatibility/skript/event/EvtCustomClick.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java index c5c367cf8..c931f780d 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java @@ -31,8 +31,8 @@ public class EvtCustomClick extends SkriptEvent { @SuppressWarnings("unchecked") public static void register() { Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class}, - "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (custom|ce|craft-engine) item[s] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", - "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (custom|ce|craft-engine) item[s] (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%"); + "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (ce|craft-engine) [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", + "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (ce|craft-engine) (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%"); } private @Nullable Literal type; From 226238028514bc4da8b98e6b9c33ed0c31c8c421 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 8 Aug 2025 22:26:43 +0800 Subject: [PATCH 13/57] 0.0.61.2 --- .../world/chunk/serialization/DefaultSectionSerializer.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java index f95c1bde6..e8947d094 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java @@ -31,7 +31,7 @@ public final class DefaultSectionSerializer { ReadableContainer.Serialized serialized = section.statesContainer().serialize(null, PalettedContainer.PaletteProvider.CUSTOM_BLOCK_STATE); ListTag palettes = new ListTag(); List states = serialized.paletteEntries(); - if (states.size() == 1 && states.get(0) == EmptyBlock.STATE) { + if (states.size() == 1 && states.getFirst() == EmptyBlock.STATE) { return null; } CompoundTag sectionNbt = new CompoundTag(); diff --git a/gradle.properties b/gradle.properties index 49e177021..781879cd3 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.61 +project_version=0.0.61.2 config_version=43 lang_version=23 project_group=net.momirealms From eb3a96e84e7741d4c73972b0b857140daa619709 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 9 Aug 2025 16:53:23 +0800 Subject: [PATCH 14/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E7=A0=B4=E5=9D=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/factory/ComponentItemFactory1_20_5.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index d5552f058..adc9cda5c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -345,11 +345,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory Date: Sat, 9 Aug 2025 18:30:15 +0800 Subject: [PATCH 15/57] =?UTF-8?q?refactor(resourcepack):=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E5=A2=99=E4=B8=8A=E7=9A=84=E8=8A=B1=E7=AF=AE=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/custom/flower_basket_wall.json | 162 +++++++++--------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json index b627c0756..1fbe404cf 100644 --- a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/flower_basket_wall.json @@ -6,185 +6,185 @@ }, "elements": [ { - "from": [-1, 11.5625, 4.43375], - "to": [11, 11.5625, 13.43375], - "rotation": {"angle": 45, "axis": "z", "origin": [5, 11.5625, 7.43375]}, + "from": [5, 11.5625, 2.56625], + "to": [17, 11.5625, 11.56625], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 11.5625, 8.56625]}, "faces": { "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, - "up": {"uv": [3, 4, 0, 8], "rotation": 90, "texture": "#0"}, - "down": {"uv": [3, 8, 0, 4], "rotation": 270, "texture": "#0"} + "up": {"uv": [3, 4, 0, 8], "rotation": 270, "texture": "#0"}, + "down": {"uv": [3, 8, 0, 4], "rotation": 90, "texture": "#0"} } }, { - "from": [-1, 10.0625, 4.43375], - "to": [11, 10.0625, 13.43375], - "rotation": {"angle": 45, "axis": "z", "origin": [5, 10.0625, 7.43375]}, + "from": [5, 10.0625, 2.56625], + "to": [17, 10.0625, 11.56625], + "rotation": {"angle": -45, "axis": "z", "origin": [11, 10.0625, 8.56625]}, "faces": { "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, - "up": {"uv": [6, 4, 3, 8], "rotation": 90, "texture": "#0"}, - "down": {"uv": [6, 8, 3, 4], "rotation": 270, "texture": "#0"} + "up": {"uv": [6, 4, 3, 8], "rotation": 270, "texture": "#0"}, + "down": {"uv": [6, 8, 3, 4], "rotation": 90, "texture": "#0"} } }, { - "from": [5, 11.5625, 4.43375], - "to": [17, 11.5625, 13.43375], - "rotation": {"angle": -45, "axis": "z", "origin": [11, 11.5625, 7.43375]}, + "from": [-1, 11.5625, 2.56625], + "to": [11, 11.5625, 11.56625], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 11.5625, 8.56625]}, "faces": { "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, - "up": {"uv": [3, 8, 0, 4], "rotation": 90, "texture": "#0"}, - "down": {"uv": [3, 4, 0, 8], "rotation": 270, "texture": "#0"} + "up": {"uv": [3, 8, 0, 4], "rotation": 270, "texture": "#0"}, + "down": {"uv": [3, 4, 0, 8], "rotation": 90, "texture": "#0"} } }, { - "from": [5, 10.0625, 4.43375], - "to": [17, 10.0625, 13.43375], - "rotation": {"angle": -45, "axis": "z", "origin": [11, 10.0625, 7.43375]}, + "from": [-1, 10.0625, 2.56625], + "to": [11, 10.0625, 11.56625], + "rotation": {"angle": 45, "axis": "z", "origin": [5, 10.0625, 8.56625]}, "faces": { "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, - "up": {"uv": [6, 8, 3, 4], "rotation": 90, "texture": "#0"}, - "down": {"uv": [6, 4, 3, 8], "rotation": 270, "texture": "#0"} + "up": {"uv": [6, 8, 3, 4], "rotation": 270, "texture": "#0"}, + "down": {"uv": [6, 4, 3, 8], "rotation": 90, "texture": "#0"} } }, { - "from": [2, 10.0625, 4.43375], - "to": [14, 10.0625, 16.43375], - "rotation": {"angle": 45, "axis": "x", "origin": [8, 10.0625, 10.43375]}, + "from": [2, 10.0625, -0.43375], + "to": [14, 10.0625, 11.56625], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 10.0625, 5.56625]}, "faces": { "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, - "up": {"uv": [4, 12, 0, 16], "texture": "#0"}, - "down": {"uv": [0, 12, 4, 16], "rotation": 180, "texture": "#0"} + "up": {"uv": [4, 12, 0, 16], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 12, 4, 16], "texture": "#0"} } }, { - "from": [2, 10.0625, 1.43375], - "to": [14, 10.0625, 13.43375], - "rotation": {"angle": -45, "axis": "x", "origin": [8, 10.0625, 7.43375]}, + "from": [2, 10.0625, 2.56625], + "to": [14, 10.0625, 14.56625], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 10.0625, 8.56625]}, "faces": { "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, - "up": {"uv": [4, 16, 0, 12], "texture": "#0"}, - "down": {"uv": [0, 16, 4, 12], "rotation": 180, "texture": "#0"} + "up": {"uv": [4, 16, 0, 12], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 16, 4, 12], "texture": "#0"} } }, { - "from": [2, 11.5625, 2.18375], - "to": [14, 11.5625, 14.18375], - "rotation": {"angle": -45, "axis": "x", "origin": [8, 11.5625, 8.18375]}, + "from": [2, 11.5625, 1.81625], + "to": [14, 11.5625, 13.81625], + "rotation": {"angle": 45, "axis": "x", "origin": [8, 11.5625, 7.81625]}, "faces": { "north": {"uv": [0, 0, 4, 0], "texture": "#0"}, "east": {"uv": [0, 0, 4, 0], "texture": "#0"}, "south": {"uv": [0, 0, 4, 0], "texture": "#0"}, "west": {"uv": [0, 0, 4, 0], "texture": "#0"}, - "up": {"uv": [4, 12, 0, 8], "texture": "#0"}, - "down": {"uv": [0, 12, 4, 8], "rotation": 180, "texture": "#0"} + "up": {"uv": [4, 12, 0, 8], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 12, 4, 8], "texture": "#0"} } }, { - "from": [2, 11.5625, 3.68375], - "to": [14, 11.5625, 15.68375], - "rotation": {"angle": 45, "axis": "x", "origin": [8, 11.5625, 9.68375]}, + "from": [2, 11.5625, 0.31625], + "to": [14, 11.5625, 12.31625], + "rotation": {"angle": -45, "axis": "x", "origin": [8, 11.5625, 6.31625]}, "faces": { "north": {"uv": [4, 0, 0, 0], "texture": "#0"}, "east": {"uv": [4, 0, 0, 0], "texture": "#0"}, "south": {"uv": [4, 0, 0, 0], "texture": "#0"}, "west": {"uv": [4, 0, 0, 0], "texture": "#0"}, - "up": {"uv": [4, 8, 0, 12], "texture": "#0"}, - "down": {"uv": [0, 8, 4, 12], "rotation": 180, "texture": "#0"} + "up": {"uv": [4, 8, 0, 12], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 8, 4, 12], "texture": "#0"} } }, { - "from": [3.5, 7.0625, 5.93375], - "to": [12.5, 8.5625, 11.93375], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "from": [3.5, 7.0625, 4.06625], + "to": [12.5, 8.5625, 10.06625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 8.56625]}, "faces": { "north": {"uv": [13.5, 15.5, 10.5, 16], "texture": "#0"}, "east": {"uv": [9, 15.5, 7, 16], "texture": "#0"}, "south": {"uv": [13.5, 15.5, 10.5, 16], "texture": "#0"}, "west": {"uv": [9, 15.5, 7, 16], "texture": "#0"}, - "up": {"uv": [11.5, 6.5, 13.5, 3.5], "rotation": 90, "texture": "#0"}, - "down": {"uv": [11.5, 6.5, 13.5, 9.5], "rotation": 270, "texture": "#0"} + "up": {"uv": [11.5, 6.5, 13.5, 3.5], "rotation": 270, "texture": "#0"}, + "down": {"uv": [11.5, 6.5, 13.5, 9.5], "rotation": 90, "texture": "#0"} } }, { - "from": [4.25, 3.3125, 6.68375], - "to": [11.75, 7.0625, 11.18375], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "from": [4.25, 3.3125, 4.81625], + "to": [11.75, 7.0625, 9.31625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 8.56625]}, "faces": { "north": {"uv": [16, 14.75, 13.5, 16], "texture": "#0"}, "east": {"uv": [10.5, 14.75, 9, 16], "texture": "#0"}, "south": {"uv": [16, 14.75, 13.5, 16], "texture": "#0"}, "west": {"uv": [10.5, 14.75, 9, 16], "texture": "#0"}, - "up": {"uv": [8, 14.75, 10.5, 12.25], "rotation": 90, "texture": "#0"}, - "down": {"uv": [9, 9.75, 10.5, 12.25], "rotation": 270, "texture": "#0"} + "up": {"uv": [8, 14.75, 10.5, 12.25], "rotation": 270, "texture": "#0"}, + "down": {"uv": [9, 9.75, 10.5, 12.25], "rotation": 90, "texture": "#0"} } }, { - "from": [4.1, 3.1625, 6.53375], - "to": [11.9, 7.2125, 11.33375], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 7.43375]}, + "from": [4.1, 3.1625, 4.66625], + "to": [11.9, 7.2125, 9.46625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.5, 8.56625]}, "faces": { "north": {"uv": [16, 8.5, 13.5, 9.75], "texture": "#0"}, - "east": {"uv": [16, 8.5, 14.5, 9.75], "texture": "#0"}, + "east": {"uv": [14.5, 8.5, 16, 9.75], "texture": "#0"}, "south": {"uv": [16, 8.5, 13.5, 9.75], "texture": "#0"}, - "west": {"uv": [14.5, 8.5, 16, 9.75], "texture": "#0"}, - "up": {"uv": [13.5, 8.5, 16, 6], "rotation": 90, "texture": "#0"}, - "down": {"uv": [15, 3.5, 13.5, 6], "rotation": 270, "texture": "#0"} + "west": {"uv": [16, 8.5, 14.5, 9.75], "texture": "#0"}, + "up": {"uv": [13.5, 8.5, 16, 6], "rotation": 270, "texture": "#0"}, + "down": {"uv": [15, 3.5, 13.5, 6], "rotation": 90, "texture": "#0"} } }, { - "from": [0.5, 3.3125, 8.93375], - "to": [15.5, 15.3125, 8.93375], - "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 9.3125, 8.93375]}, + "from": [0.5, 3.3125, 7.06625], + "to": [15.5, 15.3125, 7.06625], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 9.3125, 7.06625]}, "faces": { - "north": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "north": {"uv": [0, 0, 4, 4], "texture": "#0"}, "east": {"uv": [0, 0, 0, 4], "texture": "#0"}, - "south": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 4], "texture": "#0"}, "west": {"uv": [0, 0, 0, 4], "texture": "#0"}, - "up": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"}, - "down": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"} + "up": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"} } }, { - "from": [0.5, 3.3125, 8.93375], - "to": [15.5, 15.3125, 8.93375], - "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 9.3125, 8.93375]}, + "from": [0.5, 3.3125, 7.06625], + "to": [15.5, 15.3125, 7.06625], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 9.3125, 7.06625]}, "faces": { - "north": {"uv": [4, 0, 0, 4], "texture": "#0"}, + "north": {"uv": [0, 0, 4, 4], "texture": "#0"}, "east": {"uv": [0, 0, 0, 4], "texture": "#0"}, - "south": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "south": {"uv": [4, 0, 0, 4], "texture": "#0"}, "west": {"uv": [0, 0, 0, 4], "texture": "#0"}, - "up": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"}, - "down": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"} + "up": {"uv": [0, 0, 0, 4], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 4], "rotation": 90, "texture": "#0"} } }, { - "from": [5, 3.3125, 4.44125], - "to": [11, 5.5625, 6.69125], - "rotation": {"angle": 0, "axis": "y", "origin": [10.25, 3.3125, 5.93375]}, + "from": [5, 3.3125, 9.30875], + "to": [11, 5.5625, 11.55875], + "rotation": {"angle": 0, "axis": "y", "origin": [5.75, 3.3125, 10.06625]}, "faces": { - "north": {"uv": [16, 0, 14, 0.75], "texture": "#0"}, - "east": {"uv": [14, 2.75, 13.25, 3.5], "texture": "#0"}, - "south": {"uv": [16, 0.75, 14, 1.5], "texture": "#0"}, - "west": {"uv": [13.25, 2.75, 14, 3.5], "texture": "#0"}, - "up": {"uv": [13.25, 0, 12.5, 2], "rotation": 90, "texture": "#0"}, - "down": {"uv": [14, 0, 13.25, 2], "rotation": 270, "texture": "#0"} + "north": {"uv": [16, 0.75, 14, 1.5], "texture": "#0"}, + "east": {"uv": [13.25, 2.75, 14, 3.5], "texture": "#0"}, + "south": {"uv": [16, 0, 14, 0.75], "texture": "#0"}, + "west": {"uv": [14, 2.75, 13.25, 3.5], "texture": "#0"}, + "up": {"uv": [13.25, 0, 12.5, 2], "rotation": 270, "texture": "#0"}, + "down": {"uv": [14, 0, 13.25, 2], "rotation": 90, "texture": "#0"} } } ], @@ -225,7 +225,7 @@ "groups": [ { "name": "bone2", - "origin": [-5, 5.3125, -4.43375], + "origin": [-5, 5.3125, -3.30125], "color": 0, "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] } From 23c380f3f71d53885ff61ff6fa22223f87da7cee Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 10 Aug 2025 09:30:47 +0800 Subject: [PATCH 16/57] =?UTF-8?q?fix(item):=20=E4=BF=AE=E5=A4=8D=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=A0=B4=E5=9D=8F=E6=95=B0=E6=8D=AE=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/factory/ComponentItemFactory1_20_5.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index adc9cda5c..2fd281320 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -345,7 +345,12 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory Date: Sun, 10 Aug 2025 10:01:43 +0800 Subject: [PATCH 17/57] =?UTF-8?q?feat(default-assets):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=A3=8B=E7=9B=98=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/block_name.yml | 4 +- .../default/configuration/blocks.yml | 71 ++++++++++++++++++ .../default/configuration/categories.yml | 3 +- .../resources/default/configuration/i18n.yml | 2 + .../textures/block/custom/chessboard.png | Bin 0 -> 719 bytes 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png diff --git a/common-files/src/main/resources/resources/default/configuration/block_name.yml b/common-files/src/main/resources/resources/default/configuration/block_name.yml index 5619af49a..0b89fc743 100644 --- a/common-files/src/main/resources/resources/default/configuration/block_name.yml +++ b/common-files/src/main/resources/resources/default/configuration/block_name.yml @@ -26,6 +26,7 @@ lang: block_name:default:gunpowder_block: GunPowder Block block_name:default:solid_gunpowder_block: Solid GunPowder Block block_name:default:copper_coil: Copper Coil + block_name:default:chessboard: Chessboard zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -49,4 +50,5 @@ lang: block_name:default:ender_pearl_flower: 末影珍珠花 block_name:default:gunpowder_block: 火药粉末 block_name:default:solid_gunpowder_block: 凝固火药块 - block_name:default:copper_coil: 铜线圈 \ No newline at end of file + block_name:default:copper_coil: 铜线圈 + block_name:default:chessboard: 棋盘 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks.yml b/common-files/src/main/resources/resources/default/configuration/blocks.yml index f97b2da35..8df0578c9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks.yml @@ -364,6 +364,77 @@ items#misc: pebble=3: appearance: 'three' id: 4 + default:chessboard: + material: nether_brick + custom-model-data: 3006 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/chessboard + generation: + parent: minecraft:block/custom/chessboard + behavior: + type: block_item + block: + loot: + template: default:loot_table/self + settings: + hardness: 1.4 + resistance: 1.4 + is-suffocating: true + is-redstone-conductor: true + push-reaction: PUSH_ONLY + instrument: BASEDRUM + map-color: 36 + sounds: + break: minecraft:block.stone.break + fall: minecraft:block.stone.fall + hit: minecraft:block.stone.hit + place: minecraft:block.stone.place + step: minecraft:block.stone.step + states: + properties: + facing: + type: 4-direction + default: north + appearances: + east: + state: note_block:18 + model: + path: minecraft:block/custom/chessboard + y: 270 + generation: + parent: minecraft:block/template_glazed_terracotta + textures: + pattern: minecraft:block/custom/chessboard + north: + state: note_block:19 + model: + path: minecraft:block/custom/chessboard + y: 180 + south: + state: note_block:20 + model: + path: minecraft:block/custom/chessboard + west: + state: note_block:21 + model: + path: minecraft:block/custom/chessboard + y: 90 + variants: + facing=east: + appearance: east + id: 18 + facing=north: + appearance: north + id: 19 + facing=south: + appearance: south + id: 20 + facing=west: + appearance: west + id: 21 recipes#misc: default:chinese_lantern: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 10ef8b0f2..248c46162 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -77,4 +77,5 @@ categories: - default:copper_coil - default:flame_elytra - default:cap - - default:pebble \ No newline at end of file + - default:pebble + - default:chessboard \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index b032f9c78..be1f59d04 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -45,6 +45,7 @@ i18n: item.pebble: Pebble item.cap: Cap item.flower_basket: Flower Basket + item.chessboard: Chessboard category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -100,6 +101,7 @@ i18n: item.pebble: 石子 item.cap: 鸭舌帽 item.flower_basket: 花篮 + item.chessboard: 棋盘 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png new file mode 100644 index 0000000000000000000000000000000000000000..97ebb52c9ddf530347479f0c3b1d68d5f0698007 GIT binary patch literal 719 zcmV;=0x1DAFRWC)$QmOf~k(M6mp#X+R_Tm&hO z7IacXm+Ds9TAHMVHc6Xzljc5-`Tme19=P1gJ^%S$|9@2W_gCF$G+?_PY}*D`C=@~_ zw~v*T6})=$PX1}FvaL}yq4PW z@o}is&o4Tc%ZWq+aFgHpVhPD)QWWg$>e~4;n#lCV45)+wc}@c(BO{2%O;NUR0?mIVAiz+bXLyopfB^a%g}002ovPDHLkV1ka2 BR9OH3 literal 0 HcmV?d00001 From 1aed961edfe9c17829dde83cd82b05025c3e42d0 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 10 Aug 2025 15:20:16 +0800 Subject: [PATCH 18/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E7=A0=B4=E5=9D=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/factory/ComponentItemFactory1_20_5.java | 6 +++++- gradle.properties | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index adc9cda5c..3dfeab143 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -345,7 +345,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory Date: Sun, 10 Aug 2025 15:33:48 +0800 Subject: [PATCH 19/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineBlocks.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index f13128275..ffddee806 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -56,6 +56,22 @@ public final class CraftEngineBlocks { return place(location, block, UpdateOption.UPDATE_ALL, playSound); } + /** + * Place a custom block + * + * @param location location + * @param blockId block owner id + * @param playSound whether to play place sounds + * @return success or not + */ + public static boolean place(@NotNull Location location, + @NotNull Key blockId, + boolean playSound) { + CustomBlock block = byId(blockId); + if (block == null) return false; + return place(location, block.defaultState(), UpdateOption.UPDATE_ALL, playSound); + } + /** * Place a custom block with given properties * From 49f5303933111dd5f3e25ea86b5537ca1554c32a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 10 Aug 2025 20:06:43 +0800 Subject: [PATCH 20/57] =?UTF-8?q?=E6=9B=B4=E6=96=B0wiki=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/config.yml | 3 +-- common-files/src/main/resources/translations/de.yml | 2 +- common-files/src/main/resources/translations/en.yml | 2 +- common-files/src/main/resources/translations/es.yml | 2 +- common-files/src/main/resources/translations/ru_ru.yml | 2 +- common-files/src/main/resources/translations/tr.yml | 2 +- common-files/src/main/resources/translations/zh_cn.yml | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index f7ea43ab2..66e7060f0 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -82,7 +82,7 @@ resource-pack: prompt: "To fully experience our server,please accept our custom resource pack." # If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc # If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery. - # Read this page for more host types: https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host + # Read this page for more host types: https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host hosting: - type: "self" ip: "localhost" @@ -171,7 +171,6 @@ block: # - Sending custom IDs (e.g., craftengine:note_block_0) to vanilla clients WILL CRASH THEM! # ✅ Solution: # - Use `client-bound-item-data` to safely sync custom block data to clients. - # Documentation: https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/add-new-contents/items/item-data/client-bound-item-data simplify-adventure-break-check: false # Similar to the option above, but designed for block placement simplify-adventure-place-check: false diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 8f505365b..3cbda8827 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -303,7 +303,7 @@ warning.config.loot_table.entry.item.missing_item: "Problem in Datei Problem in Datei gefunden - '' hat eine falsch konfigurierte Beutetabelle, einer der Bedingungen fehlt das erforderliche 'type'-Argument." warning.config.loot_table.condition.invalid_type: "Problem in Datei gefunden - '' hat eine falsch konfigurierte Beutetabelle, einer der Bedingungen verwendet einen ungültigen Bedingungstyp ''." warning.config.host.missing_type: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Fehlendes erforderliches 'type'-Argument für den Host." -warning.config.host.invalid_type: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Host-Typ '' ist ungültig. Bitte lesen Sie https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host." +warning.config.host.invalid_type: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Host-Typ '' ist ungültig. Bitte lesen Sie https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host." warning.config.host.external.missing_url: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Fehlendes erforderliches 'url'-Argument für den externen Host." warning.config.host.alist.missing_api_url: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Fehlendes erforderliches 'api-url'-Argument für den AList-Host." warning.config.host.alist.missing_username: "Problem in config.yml im Abschnitt 'resource-pack.delivery.hosting' gefunden - Fehlendes erforderliches 'username'-Argument oder Umgebungsvariable 'CE_ALIST_USERNAME' für den AList-Host." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index fedd0c09a..dc3cdb95c 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -327,7 +327,7 @@ warning.config.loot_table.entry.item.missing_item: "Issue found in file warning.config.loot_table.condition.missing_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is missing the required 'type' argument." warning.config.loot_table.condition.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is using an invalid condition type ''." warning.config.host.missing_type: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'type' argument for host." -warning.config.host.invalid_type: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Host type '' is invalid. Please read https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host." +warning.config.host.invalid_type: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Host type '' is invalid. Please read https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host." warning.config.host.external.missing_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'url' argument for external host." warning.config.host.alist.missing_api_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'api-url' argument for alist host." warning.config.host.alist.missing_username: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'username' argument or environment variable 'CE_ALIST_USERNAME' for alist host." diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 9eb382a17..4306e0579 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -232,7 +232,7 @@ warning.config.loot_table.condition.table_bonus.missing_chances: "Proble warning.config.loot_table.number.missing_type: "Problema encontrado en el archivo - '' tiene una tabla de botín mal configurada, uno de los números carece del argumento requerido 'type'." warning.config.loot_table.number.invalid_type: "Problema encontrado en el archivo - '' tiene una tabla de botín mal configurada, uno de los números está usando un tipo de número inválido ''." warning.config.host.missing_type: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Argumento requerido 'type' faltante para el host." -warning.config.host.invalid_type: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Tipo de host '' inválido. Por favor lee https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host" +warning.config.host.invalid_type: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Tipo de host '' inválido. Por favor lee https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host" warning.config.host.external.missing_url: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Argumento requerido 'url' faltante para el host externo." warning.config.host.alist.missing_api_url: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Argumento requerido 'api-url' faltante para el host alist." warning.config.host.alist.missing_username: "Problema encontrado en config.yml en la sección 'resource-pack.delivery.hosting' - Argumento requerido 'username' o variable de entorno 'CE_ALIST_USERNAME' faltante para el host alist." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index 73b8fa55b..626e314d6 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -302,7 +302,7 @@ warning.config.loot_table.entry.item.missing_item: "Проблема н warning.config.loot_table.condition.missing_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в одном из условий отсутствует необходимый 'type' аргумент." warning.config.loot_table.condition.invalid_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, одно из условий имеет недействительный тип условия ''." warning.config.host.missing_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'type' аргумент для хостинга." -warning.config.host.invalid_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Тип хоста '' недействителен. Пожалуйста, прочитайте https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host." +warning.config.host.invalid_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Тип хоста '' недействителен. Пожалуйста, прочитайте https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host." warning.config.host.external.missing_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'url' аргумент для внешнего хоста." warning.config.host.alist.missing_api_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'api-url' аргумент для alist хостинга." warning.config.host.alist.missing_username: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'username' аргумент или переменная среды 'CE_ALIST_USERNAME' для alist хостинга." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index c8d9cc602..b1d73071c 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -226,7 +226,7 @@ warning.config.loot_table.entry.item.missing_item: " dosyasında warning.config.loot_table.condition.missing_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri için gerekli 'type' argümanı eksik." warning.config.loot_table.condition.invalid_type: " dosyasında sorun bulundu - '', yanlış yapılandırılmış bir ganimet tablosuna sahip, koşullardan biri geçersiz bir koşul türü '' kullanıyor." warning.config.host.missing_type: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host için gerekli 'type' argümanı eksik." -warning.config.host.invalid_type: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host türü '' geçersiz. Lütfen https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host sayfasını okuyun." +warning.config.host.invalid_type: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Host türü '' geçersiz. Lütfen https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host sayfasını okuyun." warning.config.host.external.missing_url: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - Harici host için gerekli 'url' argümanı eksik." warning.config.host.alist.missing_api_url: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - alist host için gerekli 'api-url' argümanı eksik." warning.config.host.alist.missing_username: "config.yml dosyasında 'resource-pack.delivery.hosting' bölümünde sorun bulundu - alist host için gerekli 'username' argümanı veya 'CE_ALIST_USERNAME' ortam değişkeni eksik." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 7a22c1732..4adec7286 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -327,7 +327,7 @@ warning.config.loot_table.entry.item.missing_item: "在文件 warning.config.loot_table.condition.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件缺少必需的 'type' 参数" warning.config.loot_table.condition.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件使用了无效的条件类型 ''" warning.config.host.missing_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数" -warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host" +warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host" warning.config.host.external.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数" warning.config.host.alist.missing_api_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'api-url' 参数" warning.config.host.alist.missing_username: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'username' 参数或环境变量 'CE_ALIST_USERNAME'" From 969ab57b48b4c31cc8afd2e3a36ee70ec650356e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 10 Aug 2025 21:04:11 +0800 Subject: [PATCH 21/57] =?UTF-8?q?refactor(i18n):=20=E6=9B=B4=E6=94=B9?= =?UTF-8?q?=E7=AE=80=E4=BD=93=E4=B8=AD=E6=96=87=E8=AF=AD=E8=A8=80=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E9=93=BE=E6=8E=A5=E5=88=B0=E5=9B=BD=E5=86=85?= =?UTF-8?q?=E9=95=9C=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/translations/zh_cn.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 4adec7286..da8ae3198 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -327,7 +327,7 @@ warning.config.loot_table.entry.item.missing_item: "在文件 warning.config.loot_table.condition.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件缺少必需的 'type' 参数" warning.config.loot_table.condition.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件使用了无效的条件类型 ''" warning.config.host.missing_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数" -warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host" +warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://ce.gtemc.cn/zh-Hans/getting_start/set_up_host" warning.config.host.external.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数" warning.config.host.alist.missing_api_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'api-url' 参数" warning.config.host.alist.missing_username: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'username' 参数或环境变量 'CE_ALIST_USERNAME'" From 668f3d24c8e0a73ed92890d1306d066a253d5ab6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 11 Aug 2025 02:01:49 +0800 Subject: [PATCH 22/57] =?UTF-8?q?=E6=94=B9=E5=96=84get=20item=E6=89=8B?= =?UTF-8?q?=E6=84=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 6 ++-- .../command/feature/GetItemCommand.java | 22 +++++++++---- .../command/feature/GiveItemCommand.java | 23 ++++++++----- .../default/configuration/blocks.yml | 31 ++++++++++++------ .../default/configuration/categories.yml | 2 +- .../resources/default/configuration/i18n.yml | 4 +-- .../textures/block/custom/chessboard.png | Bin 719 -> 0 bytes .../block/custom/chessboard_block.png | Bin 0 -> 446 bytes .../core/item/AbstractItemManager.java | 22 +++++++++---- .../craftengine/core/item/ItemManager.java | 2 ++ .../core/pack/AbstractPackManager.java | 1 + gradle.properties | 2 +- 12 files changed, 76 insertions(+), 39 deletions(-) delete mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard_block.png diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 4d58dca43..39c1f336c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -335,7 +335,7 @@ public class BukkitItemManager extends AbstractItemManager { @Override public ItemStack buildCustomItemStack(Key id, Player player) { - return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); + return Optional.ofNullable(this.customItemsById.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); } @Override @@ -349,12 +349,12 @@ public class BukkitItemManager extends AbstractItemManager { @Override public Item createCustomWrappedItem(Key id, Player player) { - return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItem(player)).orElse(null); + return Optional.ofNullable(customItemsById.get(id)).map(it -> it.buildItem(player)).orElse(null); } @Override public Item createWrappedItem(Key id, @Nullable Player player) { - CustomItem customItem = this.customItems.get(id); + CustomItem customItem = this.customItemsById.get(id); if (customItem != null) { return customItem.buildItem(player); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java index 598167971..4005e7e5d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java @@ -1,8 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.PlayerUtils; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.FlagKeys; @@ -47,12 +51,18 @@ public class GetItemCommand extends BukkitCommandFeature { int amount = context.getOrDefault("amount", 1); boolean toInv = context.flags().hasFlag(FlagKeys.TO_INVENTORY); NamespacedKey namespacedKey = context.get("id"); - Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); - ItemStack builtItem = plugin().itemManager().buildCustomItemStack(key, plugin().adapt(context.sender())); - if (builtItem == null) { - handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_FAILURE_NOT_EXIST, Component.text(key.toString())); - return; + Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); + CustomItem customItem = CraftEngineItems.byId(itemId); + if (customItem == null) { + customItem = BukkitItemManager.instance().getCustomItemByPathOnly(itemId.value()).orElse(null); + if (customItem == null) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_FAILURE_NOT_EXIST, Component.text(itemId.toString())); + return; + } else { + itemId = customItem.id(); + } } + ItemStack builtItem = customItem.buildItemStack(plugin().adapt(context.sender())); int amountToGive = amount; int maxStack = builtItem.getMaxStackSize(); while (amountToGive > 0) { @@ -66,7 +76,7 @@ public class GetItemCommand extends BukkitCommandFeature { PlayerUtils.dropItem(player, more, false, true, false); } } - handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_SUCCESS, Component.text(amount), Component.text(key.toString())); + handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_SUCCESS, Component.text(amount), Component.text(itemId.toString())); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java index f258b70f4..430ee64be 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.PlayerUtils; @@ -54,16 +55,20 @@ public class GiveItemCommand extends BukkitCommandFeature { int amount = context.getOrDefault("amount", 1); boolean toInv = context.flags().hasFlag(FlagKeys.TO_INVENTORY); NamespacedKey namespacedKey = context.get("id"); - Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); - Optional> optionalItem = BukkitItemManager.instance().getCustomItem(key); - if (optionalItem.isEmpty()) { - handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_FAILURE_NOT_EXIST, Component.text(key.toString())); - return; + Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); + CustomItem customItem = CraftEngineItems.byId(itemId); + if (customItem == null) { + customItem = BukkitItemManager.instance().getCustomItemByPathOnly(itemId.value()).orElse(null); + if (customItem == null) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_FAILURE_NOT_EXIST, Component.text(itemId.toString())); + return; + } else { + itemId = customItem.id(); + } } - Collection players = selector.values(); for (Player player : players) { - ItemStack builtItem = optionalItem.get().buildItemStack(plugin().adapt(player)); + ItemStack builtItem = customItem.buildItemStack(plugin().adapt(player)); if (builtItem == null) { return; } @@ -90,9 +95,9 @@ public class GiveItemCommand extends BukkitCommandFeature { } } if (players.size() == 1) { - handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_SINGLE, Component.text(amount), Component.text(key.toString()), Component.text(players.iterator().next().getName())); + handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_SINGLE, Component.text(amount), Component.text(itemId.toString()), Component.text(players.iterator().next().getName())); } else if (players.size() > 1) { - handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_MULTIPLE, Component.text(amount), Component.text(key.toString()), Component.text(players.size())); + handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_MULTIPLE, Component.text(amount), Component.text(itemId.toString()), Component.text(players.size())); } }); } diff --git a/common-files/src/main/resources/resources/default/configuration/blocks.yml b/common-files/src/main/resources/resources/default/configuration/blocks.yml index 8df0578c9..530b5f9b9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks.yml @@ -364,16 +364,16 @@ items#misc: pebble=3: appearance: 'three' id: 4 - default:chessboard: + default:chessboard_block: material: nether_brick custom-model-data: 3006 data: - item-name: + item-name: model: type: minecraft:model - path: minecraft:item/custom/chessboard + path: minecraft:item/custom/chessboard_block generation: - parent: minecraft:block/custom/chessboard + parent: minecraft:block/custom/chessboard_block behavior: type: block_item block: @@ -402,25 +402,25 @@ items#misc: east: state: note_block:18 model: - path: minecraft:block/custom/chessboard + path: minecraft:block/custom/chessboard_block y: 270 generation: parent: minecraft:block/template_glazed_terracotta textures: - pattern: minecraft:block/custom/chessboard + pattern: minecraft:block/custom/chessboard_block north: state: note_block:19 model: - path: minecraft:block/custom/chessboard + path: minecraft:block/custom/chessboard_block y: 180 south: state: note_block:20 model: - path: minecraft:block/custom/chessboard + path: minecraft:block/custom/chessboard_block west: state: note_block:21 model: - path: minecraft:block/custom/chessboard + path: minecraft:block/custom/chessboard_block y: 90 variants: facing=east: @@ -506,4 +506,15 @@ recipes#misc: A: default:pebble result: id: minecraft:cobblestone - count: 1 \ No newline at end of file + count: 1 + default:chessboard_block: + type: shaped + pattern: + - AB + - BA + ingredients: + A: minecraft:white_terracotta + B: minecraft:black_terracotta + result: + id: default:chessboard_block + count: 4 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 248c46162..79c4e3fa9 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -78,4 +78,4 @@ categories: - default:flame_elytra - default:cap - default:pebble - - default:chessboard \ No newline at end of file + - default:chessboard_block \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index be1f59d04..a2cfc0ddc 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -45,7 +45,7 @@ i18n: item.pebble: Pebble item.cap: Cap item.flower_basket: Flower Basket - item.chessboard: Chessboard + item.chessboard_block: Chessboard Block category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -101,7 +101,7 @@ i18n: item.pebble: 石子 item.cap: 鸭舌帽 item.flower_basket: 花篮 - item.chessboard: 棋盘 + item.chessboard_block: 棋盘方块 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard.png deleted file mode 100644 index 97ebb52c9ddf530347479f0c3b1d68d5f0698007..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 719 zcmV;=0x1DAFRWC)$QmOf~k(M6mp#X+R_Tm&hO z7IacXm+Ds9TAHMVHc6Xzljc5-`Tme19=P1gJ^%S$|9@2W_gCF$G+?_PY}*D`C=@~_ zw~v*T6})=$PX1}FvaL}yq4PW z@o}is&o4Tc%ZWq+aFgHpVhPD)QWWg$>e~4;n#lCV45)+wc}@c(BO{2%O;NUR0?mIVAiz+bXLyopfB^a%g}002ovPDHLkV1ka2 BR9OH3 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard_block.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard_block.png new file mode 100644 index 0000000000000000000000000000000000000000..b67b4bb2a47e8a1f29f80f298a077f94297d5884 GIT binary patch literal 446 zcmV;v0YUzWP)Px$cu7P-R5*=wlR>W2Pz*(n?H4|)V9F}kQa8qsA?$!<@CEv66e(&YlHb^7;G}7b z>Penr`}*GJ`{dWpAIX#Ghck!6;aQsFc%lIeZ@K&kOXZC?kj*+A};|Xc?tZ6YBOc=eKJ5Sh2Hi?kWTU0 zF%?V&-m7}?KuxPzHp=V_ik0B=0x3wR*S`R&N_b#qxZiRsrFH05SV@-oz9=HrfsU9W zc5S2e!ki(=6XEe+!8W;n zeWkq^=}{5_l4P2*ILCI&Pr_74FMnhtkqPVS6~N2@K}}Ir9yNI+Vp4wbI_Ju+d_dkw zkOzSFVr)!>-EbfU;E{Wiup4HLq7Q;p>I1N_OOVV}2ACM4jXNEZs0m_Ho_NpeJ89QF o`wF>z*XV~c(+vB|lDkLt4>5wzS5hggcK`qY07*qoM6N<$f_odq@Bjb+ literal 0 HcmV?d00001 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 77d581dc1..8e8b9e043 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 @@ -40,7 +40,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl private final ItemParser itemParser; private final EquipmentParser equipmentParser; protected final Map> externalItemSources = new HashMap<>(); - protected final Map> customItems = new HashMap<>(); + protected final Map> customItemsById = new HashMap<>(); + protected final Map> customItemsByPath = new HashMap<>(); protected final Map> customItemTags = new HashMap<>(); protected final Map> cmdConflictChecker = new HashMap<>(); protected final Map modernItemModels1_21_4 = new HashMap<>(); @@ -105,7 +106,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public void unload() { super.clearModelsToGenerate(); - this.customItems.clear(); + this.customItemsById.clear(); + this.customItemsByPath.clear(); this.cachedSuggestions.clear(); this.cachedTotemSuggestions.clear(); this.legacyOverrides.clear(); @@ -129,14 +131,20 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public Optional> getCustomItem(Key key) { - return Optional.ofNullable(this.customItems.get(key)); + return Optional.ofNullable(this.customItemsById.get(key)); + } + + @Override + public Optional> getCustomItemByPathOnly(String path) { + return Optional.ofNullable(this.customItemsByPath.get(path)); } @Override public boolean addCustomItem(CustomItem customItem) { Key id = customItem.id(); - if (this.customItems.containsKey(id)) return false; - this.customItems.put(id, customItem); + if (this.customItemsById.containsKey(id)) return false; + this.customItemsById.put(id, customItem); + this.customItemsByPath.put(id.value(), customItem); if (!customItem.isVanillaItem()) { // cache command suggestions this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); @@ -199,7 +207,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public Collection items() { - return Collections.unmodifiableCollection(this.customItems.keySet()); + return Collections.unmodifiableCollection(this.customItemsById.keySet()); } @Override @@ -302,7 +310,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public void parseSection(Pack pack, Path path, Key id, Map section) { - if (AbstractItemManager.this.customItems.containsKey(id)) { + if (AbstractItemManager.this.customItemsById.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index e1c18038d..9be0dfb7f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -76,6 +76,8 @@ public interface ItemManager extends Manageable, ModelGenerator { return getVanillaItem(key); } + Optional> getCustomItemByPathOnly(String path); + boolean addCustomItem(CustomItem customItem); default List itemIdsByTag(Key tag) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 478d3e5bd..714cc2f60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -415,6 +415,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chessboard_block.png"); // items plugin.saveResource("resources/default/configuration/items.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_rod.png"); diff --git a/gradle.properties b/gradle.properties index 1cf25188b..199f62c5e 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.61.3 +project_version=0.0.61.4 config_version=43 lang_version=23 project_group=net.momirealms From 5c6e34b3bbdeb86cebfc6a09c3392102b7ae29b9 Mon Sep 17 00:00:00 2001 From: Catnies Date: Tue, 12 Aug 2025 02:59:01 +0800 Subject: [PATCH 23/57] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=88=A4=E6=96=AD=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=98=AF=E5=AE=B6=E5=85=B7=E6=97=B6=E6=9C=89?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98;=202.=E6=98=BE=E5=BC=8F?= =?UTF-8?q?=E4=B8=BA=E4=BA=8B=E4=BB=B6=E6=B7=BB=E5=8A=A0=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=AD=97=E6=AE=B5;=203.=E8=B0=83=E6=95=B4=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E8=A1=A8=E8=BE=BE=E5=BC=8F,=20custom=20ce=20?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=AD=97=E5=8F=98=E5=BE=97=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E4=BA=86;=204.=E6=94=B9=E6=94=B9=E6=88=91=E7=9A=84=E5=9E=83?= =?UTF-8?q?=E5=9C=BE=E8=8B=B1=E8=AF=AD;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CondIsCraftEngineHasBeenLoad.java | 9 ++++---- .../skript/condition/CondIsCustomBlock.java | 4 ++-- .../skript/condition/CondIsFurniture.java | 12 +++++++--- .../skript/effect/EffPlaceFurniture.java | 2 +- .../skript/effect/EffRemoveFurniture.java | 10 ++++---- .../skript/event/EvtCustomBlock.java | 21 +++++++++++++++-- .../skript/event/EvtCustomClick.java | 23 +++++++++++++++++-- .../skript/event/EvtCustomFurniture.java | 20 ++++++++++++++-- .../expression/ExprEntityFurnitureID.java | 4 ++-- 9 files changed, 81 insertions(+), 24 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java index 39483f088..71c72bcf4 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCraftEngineHasBeenLoad.java @@ -19,14 +19,15 @@ public class CondIsCraftEngineHasBeenLoad extends Condition { public static void register() { Skript.registerCondition(CondIsCraftEngineHasBeenLoad.class, - "(ce|craft-engine) has been load[ed]", - "(ce|craft-engine) has not been load[ed] [yet]" + "(ce|craft[-]engine) (has been|is) load[ed]", + "(ce|craft[-]engine) (has not been|is not) load[ed] [yet]", + "(ce|craft[-]engine) (hasn't been|isn't) load[ed] [yet]" ); } @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - setNegated(matchedPattern == 1); + setNegated(matchedPattern >= 1); return true; } @@ -38,7 +39,7 @@ public class CondIsCraftEngineHasBeenLoad extends Condition { @Override public String toString(@Nullable Event event, boolean debug) { - return "craft-engine has " + (isNegated() ? "not " : "") + "been loaded"; + return "craft-engine " + (isNegated() ? "is not" : "is") + " loaded"; } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java index 3fc6fed21..8056b0427 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsCustomBlock.java @@ -15,8 +15,8 @@ public class CondIsCustomBlock extends Condition { public static void register() { Skript.registerCondition(CondIsCustomBlock.class, - "%blocks% (is|are) (custom|ce|craft-engine) block(s)", - "%blocks% (is|are)(n't| not) (custom|ce|craft-engine) block(s)"); + "%blocks% (is|are) [a[n]] (custom|ce|craft-engine) block[s]", + "%blocks% (is|are) (n't| not) [a[n]] (custom|ce|craft-engine) block[s]"); } private Expression blocks; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java index 265cb9e00..287596ff4 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java @@ -7,23 +7,29 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import org.bukkit.entity.Entity; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; +import java.util.function.Predicate; + public class CondIsFurniture extends Condition { public static void register() { Skript.registerCondition(CondIsFurniture.class, - "%entities% (is|are) (custom|ce|craft-engine) furniture", - "%entities% (is|are)(n't| not) (custom|ce|craft-engine) furniture"); + "%entities% (is|are) [a[n]] [(custom|ce|craft-engine)] furniture[s]", + "%entities% (is|are) (n't| not) [a[n]] [(custom|ce|craft-engine)] furniture[s]"); } private Expression entities; @Override public boolean check(Event event) { - return entities.check(event, CraftEngineFurniture::isFurniture, isNegated()); + return entities.check(event, entity -> { + BukkitFurniture baseEntity = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity); + return baseEntity != null; + }, isNegated()); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java index 7b5e9284e..76dcec702 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffPlaceFurniture.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; public class EffPlaceFurniture extends Effect { public static void register() { - Skript.registerEffect(EffPlaceFurniture.class, "place (custom|ce|craft-engine) furniture %strings% [at] [%directions% %locations%]"); + Skript.registerEffect(EffPlaceFurniture.class, "place [(custom|ce|craft-engine)] furniture[s] %strings% [at] [%directions% %locations%]"); } private Expression furniture; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java index 224d7b5a9..995f3364a 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable; public class EffRemoveFurniture extends Effect { public static void register() { - Skript.registerEffect(EffRemoveFurniture.class, "remove (custom|ce|craft-engine) furniture %entities%"); + Skript.registerEffect(EffRemoveFurniture.class, "remove [(custom|ce|craft-engine)] furniture %entities%"); } private Expression entities; @@ -22,11 +22,9 @@ public class EffRemoveFurniture extends Effect { @Override protected void execute(Event e) { for (Entity entity : entities.getArray(e)) { - if (CraftEngineFurniture.isFurniture(entity)) { - Furniture bukkitFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity); - if (bukkitFurniture != null) { - bukkitFurniture.destroy(); - } + Furniture bukkitFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity); + if (bukkitFurniture != null) { + bukkitFurniture.destroy(); } } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java index d46dc3ca4..14a2dbdd4 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java @@ -7,12 +7,20 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.registrations.EventValues; import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher; import net.momirealms.craftengine.core.entity.player.InteractionHand; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -25,10 +33,19 @@ import java.util.Arrays; public class EvtCustomBlock extends SkriptEvent { public static void register() { - Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "(break[ing]|1¦min(e|ing)) of (custom|ce|craft-engine) block [[of] %-unsafeblockstatematchers%]") + Skript.registerEvent("Break Custom Block", EvtCustomBlock.class, CustomBlockBreakEvent.class, "(break[ing]|1¦min(e|ing)) of (custom|ce|craft-engine) block[s] [[of] %-unsafeblockstatematchers%]") .description("Called when a custom block is broken by a player. If you use 'on mine', only events where the broken block dropped something will call the trigger."); - Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) of (custom|ce|craft-engine) block [[of] %-unsafeblockstatematchers%]") + EventValues.registerEventValue(CustomBlockBreakEvent.class, Location.class, CustomBlockBreakEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockBreakEvent.class, Player.class, CustomBlockBreakEvent::getPlayer, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockBreakEvent.class, Block.class, CustomBlockBreakEvent::bukkitBlock, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockBreakEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); + + Skript.registerEvent("Place Custom Block", EvtCustomBlock.class, CustomBlockPlaceEvent.class, "(plac(e|ing)|build[ing]) of (custom|ce|craft-engine) block[s] [[of] %-unsafeblockstatematchers%]") .description("Called when a player places a custom block."); + EventValues.registerEventValue(CustomBlockPlaceEvent.class, Location.class, CustomBlockPlaceEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockPlaceEvent.class, Player.class, CustomBlockPlaceEvent::player, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockPlaceEvent.class, Block.class, CustomBlockPlaceEvent::bukkitBlock, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockPlaceEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); } @Nullable diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java index c931f780d..d9b04c7ab 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java @@ -9,19 +9,26 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.registrations.EventValues; import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher; import net.momirealms.craftengine.core.entity.player.InteractionHand; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.EquipmentSlot; import org.jetbrains.annotations.Nullable; import java.util.function.Predicate; -@Name("On Click with Custom Item") -@Description({"Fires when click a custom item"}) +@Name("On Click on Custom Block and Furniture") +@Description({"Fires when click on custom block and furniture"}) @Since("1.0") public class EvtCustomClick extends SkriptEvent { @@ -33,6 +40,18 @@ public class EvtCustomClick extends SkriptEvent { Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class}, "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (ce|craft-engine) [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] of (ce|craft-engine) (with|using|holding) %itemtype% on %unsafeblockstatematchers/strings%"); + + EventValues.registerEventValue(CustomBlockInteractEvent.class, Location.class, CustomBlockInteractEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockInteractEvent.class, Player.class, CustomBlockInteractEvent::player, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockInteractEvent.class, Block.class, CustomBlockInteractEvent::bukkitBlock, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockInteractEvent.class, Entity.class, event -> null, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockInteractEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); + + EventValues.registerEventValue(FurnitureInteractEvent.class, Location.class, FurnitureInteractEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureInteractEvent.class, Player.class, FurnitureInteractEvent::player, EventValues.TIME_NOW); + EventValues.registerEventValue(CustomBlockInteractEvent.class, Block.class, event -> null, EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureInteractEvent.class, Entity.class, event -> event.furniture().baseEntity(), EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureInteractEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); } private @Nullable Literal type; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java index c254c999c..e45b73a54 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java @@ -7,8 +7,15 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.registrations.EventValues; +import io.papermc.paper.event.player.PlayerTrackEntityEvent; +import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -21,10 +28,19 @@ import java.util.Arrays; public class EvtCustomFurniture extends SkriptEvent { public static void register() { - Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) of (custom|ce|craft-engine) furniture[s] [[of] %-strings%]") + Skript.registerEvent("Break Furniture", EvtCustomFurniture.class, FurnitureBreakEvent.class, "(break[ing]) of [(custom|ce|craft-engine)] furniture[s] [[of] %-strings%]") .description("Called when a furniture is broken by a player."); - Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) of (custom|ce|craft-engine) furniture[s] [[of] %-strings%]") + EventValues.registerEventValue(FurnitureBreakEvent.class, Location.class, FurnitureBreakEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureBreakEvent.class, Player.class, FurnitureBreakEvent::player, EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureBreakEvent.class, Entity.class, event -> event.furniture().baseEntity(), EventValues.TIME_NOW); + EventValues.registerEventValue(FurnitureBreakEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); + + Skript.registerEvent("Place Furniture", EvtCustomFurniture.class, FurniturePlaceEvent.class, "(plac(e|ing)|build[ing]) of [(custom|ce|craft-engine)] furniture[s] [[of] %-strings%]") .description("Called when a player places a furniture."); + EventValues.registerEventValue(FurniturePlaceEvent.class, Location.class, FurniturePlaceEvent::location, EventValues.TIME_NOW); + EventValues.registerEventValue(FurniturePlaceEvent.class, Player.class, FurniturePlaceEvent::player, EventValues.TIME_NOW); + EventValues.registerEventValue(FurniturePlaceEvent.class, Entity.class, event -> event.furniture().baseEntity(), EventValues.TIME_NOW); + EventValues.registerEventValue(FurniturePlaceEvent.class, World.class, event -> event.location().getWorld(), EventValues.TIME_NOW); } @Nullable diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java index 864dd7ebd..0e8826602 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java @@ -10,12 +10,12 @@ import java.util.Optional; public class ExprEntityFurnitureID extends SimplePropertyExpression { public static void register() { - register(ExprEntityFurnitureID.class, String.class, "(custom|ce|craft-engine) furniture [namespace] id", "entities"); + register(ExprEntityFurnitureID.class, String.class, "[(custom|ce|craft-engine)] furniture [namespace] id", "entities"); } @Override public @Nullable String convert(Object object) { - if (object instanceof Entity entity && CraftEngineFurniture.isFurniture(entity)) { + if (object instanceof Entity entity) { return Optional.ofNullable(CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity)) .map(it -> it.id().toString()) .orElse(null); From 542afa00c7f9b28f13ec9bb500ebd194d1ea4eeb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 12 Aug 2025 19:18:34 +0800 Subject: [PATCH 24/57] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A0=86=E5=8F=A0?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/StackableBlockBehavior.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java index 52fa4ba5c..bb7552b74 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java @@ -68,7 +68,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior { private void updateStackableBlock(ImmutableBlockState state, BlockPos pos, World world, Item item, Player player, InteractionHand hand) { ImmutableBlockState nextStage = state.cycle(this.amountProperty); Location location = new Location((org.bukkit.World) world.platformWorld(), pos.x(), pos.y(), pos.z()); - FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), nextStage.customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), nextStage.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); if (this.stackSound != null) { world.playBlockSound(new Vec3d(location.getX(), location.getY(), location.getZ()), this.stackSound); } From b37b88b1e1895886d8d580c2469b76556ad3715b Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 12 Aug 2025 22:15:24 +0800 Subject: [PATCH 25/57] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D=20FastA?= =?UTF-8?q?syncWorldEdit=20=E5=85=BC=E5=AE=B9=E6=80=A7=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../worldedit/FastAsyncWorldEditDelegate.java | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 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 e116d6e6c..014f81d63 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 @@ -26,10 +26,11 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.util.LazyReference; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.SectionPos; @@ -47,38 +48,44 @@ import static java.util.Objects.requireNonNull; public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { private static int[] ordinalToIbdID; private final Set chunksToSave; - private final CEWorld ceWorld; + private final LazyReference ceWorld; private final Set brokenChunks = Collections.synchronizedSet(new HashSet<>()); protected FastAsyncWorldEditDelegate(EditSessionEvent event, Extent extent) { super(extent); this.chunksToSave = new HashSet<>(); - World weWorld = event.getWorld(); - org.bukkit.World world = Bukkit.getWorld(requireNonNull(weWorld).getName()); - CEWorld ceWorld = CraftEngine.instance().worldManager().getWorld(requireNonNull(world).getUID()); - this.ceWorld = requireNonNull(ceWorld); + this.ceWorld = LazyReference.lazyReference(() -> { + World weWorld = event.getWorld(); + requireNonNull(weWorld, "WorldEdit world is null"); + org.bukkit.World world = Bukkit.getWorld(weWorld.getName()); + requireNonNull(world, () -> "WorldEdit world " + weWorld.getName() + " is not a Bukkit world"); + CEWorld ceWorld = BukkitWorldManager.instance().getWorld(world); + requireNonNull(ceWorld, () -> "WorldEdit world " + world.getName() + " is not a CraftEngine world"); + return ceWorld; + }); } public static void init() { Settings.settings().EXTENT.ALLOWED_PLUGINS.add(FastAsyncWorldEditDelegate.class.getCanonicalName()); - FaweAdapter adapter = (FaweAdapter) WorldEditPlugin.getInstance().getBukkitImplAdapter(); - Method ordinalToIbdIDMethod = ReflectionUtils.getDeclaredMethod(CachedBukkitAdapter.class, int.class.arrayType(), new String[]{"getOrdinalToIbdID"}); try { - assert ordinalToIbdIDMethod != null; - ordinalToIbdID = (int[]) ordinalToIbdIDMethod.invoke(adapter); + Method ordinalToIbdIDMethod = CachedBukkitAdapter.class.getDeclaredMethod("getOrdinalToIbdID"); // 这样获取有代码提示 + ordinalToIbdIDMethod.setAccessible(true); + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() instanceof FaweAdapter faweAdapter) { // 确保是 paper 服务器的才调用这个 + ordinalToIbdID = (int[]) ordinalToIbdIDMethod.invoke(faweAdapter); + } else { // 应该在 spigot 的服务器上用不了这个 + CraftEngine.instance().logger().warn("Failed to init FastAsyncWorldEdit compatibility, Please use the server of paper or its fork."); + return; + } } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to init FastAsyncWorldEdit compatibility", e); + CraftEngine.instance().logger().warn("Failed to init FastAsyncWorldEdit compatibility", e); + return; } WorldEdit.getInstance().getEventBus().register(new Object() { @Subscribe @SuppressWarnings("unused") public void onEditSessionEvent(EditSessionEvent event) { - World weWorld = event.getWorld(); - if (weWorld == null) return; - Extent currentExtent = event.getExtent(); - if (event.getStage() == EditSession.Stage.BEFORE_CHANGE) { - event.setExtent(new FastAsyncWorldEditDelegate(event, currentExtent)); - } + if (event.getWorld() == null || event.getStage() != EditSession.Stage.BEFORE_CHANGE) return; + event.setExtent(new FastAsyncWorldEditDelegate(event, event.getExtent())); } }); } @@ -101,6 +108,10 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { } } + private CEWorld ceWorld() { + return this.ceWorld.get(); + } + @Override public int setBlocks(final Set vset, final Pattern pattern) { this.processBlocks(vset, pattern, getMask(), null); @@ -180,10 +191,10 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { Operation operation = super.commit(); List chunks = new ArrayList<>(this.brokenChunks); this.brokenChunks.clear(); - Object worldServer = this.ceWorld.world().serverWorld(); + 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()); + CEChunk loaded = this.ceWorld().getChunkAtIfLoaded(chunk.longKey()); // only inject loaded chunks if (loaded == null) continue; injectLevelChunk(chunkSource, loaded); @@ -214,8 +225,8 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { this.brokenChunks.add(ChunkPos.of(chunkX, chunkZ)); if (BlockStateUtils.isVanillaBlock(newStateId) && BlockStateUtils.isVanillaBlock(oldStateId)) return; try { - CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ)) - .orElse(this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ))); + 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) { @@ -232,7 +243,7 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { private void saveAllChunks() { try { for (CEChunk ceChunk : this.chunksToSave) { - this.ceWorld.worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk); + this.ceWorld().worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk); } this.chunksToSave.clear(); } catch (IOException e) { From 0f714ea8a4a9e30d7aaeb92d1bd446d5d010bc3b Mon Sep 17 00:00:00 2001 From: MrPanda8 <188357680+MrPanda8@users.noreply.github.com> Date: Tue, 12 Aug 2025 22:05:47 +0300 Subject: [PATCH 26/57] Coral blocks in mappings --- common-files/src/main/resources/mappings.yml | 83 ++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index 5ba1ee4f6..40e451664 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -4320,6 +4320,89 @@ minecraft:heavy_weighted_pressure_plate[power=13]: minecraft:heavy_weighted_pres minecraft:heavy_weighted_pressure_plate[power=14]: minecraft:heavy_weighted_pressure_plate[power=1] minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pressure_plate[power=1] +# # Corals +# # Coral blocks are ideal for creating water blocks or wall-mounted blocks. But this means that the corals can no longer dry out. + +# # Brain Coral +# minecraft:dead_brain_coral[waterlogged=false]: minecraft:brain_coral[waterlogged=false] +# minecraft:dead_brain_coral[waterlogged=true]: minecraft:brain_coral[waterlogged=true] + +# minecraft:dead_brain_coral_fan[waterlogged=false]: minecraft:brain_coral_fan[waterlogged=false] +# minecraft:dead_brain_coral_fan[waterlogged=true]: minecraft:brain_coral_fan[waterlogged=true] + +# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=east] +# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=north] +# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=south] +# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=west] + +# # Bubble Coral +# minecraft:dead_bubble_coral[waterlogged=false]: minecraft:bubble_coral[waterlogged=false] +# minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] + +# minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] +# minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] + +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=east] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=west] + +# # Fire Coral +# minecraft:dead_fire_coral[waterlogged=false]: minecraft:fire_coral[waterlogged=false] +# minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] + +# minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] +# minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] + +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=east] +# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] +# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] +# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=west] + +# # Horn Coral +# minecraft:dead_horn_coral[waterlogged=false]: minecraft:horn_coral[waterlogged=false] +# minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] + +# minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] +# minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] + +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=east] +# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] +# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] +# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=west] + +# # Tube Coral +# minecraft:dead_tube_coral[waterlogged=false]: minecraft:tube_coral[waterlogged=false] +# minecraft:dead_tube_coral[waterlogged=true]: minecraft:tube_coral[waterlogged=true] + +# minecraft:dead_tube_coral_fan[waterlogged=false]: minecraft:tube_coral_fan[waterlogged=false] +# minecraft:dead_tube_coral_fan[waterlogged=true]: minecraft:tube_coral_fan[waterlogged=true] + +# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=east] +# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=north] +# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=south] +# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=west] + #### Chorus Plant #### # Chorus Plant does support transparent textures, but man... its hitbox is super weird. You're probably better off using leaves. # minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] From dc376d2f36745abcfc01af89d6fb414f4e3397dc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 16:22:34 +0800 Subject: [PATCH 27/57] Update mappings.yml --- common-files/src/main/resources/mappings.yml | 26 +++----------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index 40e451664..daf22369a 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -4280,6 +4280,7 @@ minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,wat minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] #### Grate #### +# Suitable for making glass because it is completely transparent $$>=1.20.3#grate: minecraft:copper_grate[waterlogged=false]: minecraft:waxed_copper_grate[waterlogged=false] minecraft:copper_grate[waterlogged=true]: minecraft:waxed_copper_grate[waterlogged=true] @@ -4291,6 +4292,7 @@ $$>=1.20.3#grate: minecraft:oxidized_copper_grate[waterlogged=true]: minecraft:waxed_oxidized_copper_grate[waterlogged=true] #### Pressure Plate #### +# Triggered pressure plates appear identical, even though they output different signal strengths. minecraft:light_weighted_pressure_plate[power=2]: minecraft:light_weighted_pressure_plate[power=1] minecraft:light_weighted_pressure_plate[power=3]: minecraft:light_weighted_pressure_plate[power=1] minecraft:light_weighted_pressure_plate[power=4]: minecraft:light_weighted_pressure_plate[power=1] @@ -4320,16 +4322,12 @@ minecraft:heavy_weighted_pressure_plate[power=13]: minecraft:heavy_weighted_pres minecraft:heavy_weighted_pressure_plate[power=14]: minecraft:heavy_weighted_pressure_plate[power=1] minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pressure_plate[power=1] -# # Corals -# # Coral blocks are ideal for creating water blocks or wall-mounted blocks. But this means that the corals can no longer dry out. - -# # Brain Coral +#### Corals #### +# # Coral blocks are ideal for creating water blocks or wall-mounted blocks. But you have to sacrifice its dry appearance. # minecraft:dead_brain_coral[waterlogged=false]: minecraft:brain_coral[waterlogged=false] # minecraft:dead_brain_coral[waterlogged=true]: minecraft:brain_coral[waterlogged=true] - # minecraft:dead_brain_coral_fan[waterlogged=false]: minecraft:brain_coral_fan[waterlogged=false] # minecraft:dead_brain_coral_fan[waterlogged=true]: minecraft:brain_coral_fan[waterlogged=true] - # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=east] # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=north] # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=south] @@ -4338,14 +4336,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=south] # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=west] - -# # Bubble Coral # minecraft:dead_bubble_coral[waterlogged=false]: minecraft:bubble_coral[waterlogged=false] # minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] - # minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] # minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] - # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] @@ -4354,14 +4348,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=west] - -# # Fire Coral # minecraft:dead_fire_coral[waterlogged=false]: minecraft:fire_coral[waterlogged=false] # minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] - # minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] # minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] - # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] @@ -4370,14 +4360,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=west] - -# # Horn Coral # minecraft:dead_horn_coral[waterlogged=false]: minecraft:horn_coral[waterlogged=false] # minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] - # minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] # minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] - # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] @@ -4386,14 +4372,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=west] - -# # Tube Coral # minecraft:dead_tube_coral[waterlogged=false]: minecraft:tube_coral[waterlogged=false] # minecraft:dead_tube_coral[waterlogged=true]: minecraft:tube_coral[waterlogged=true] - # minecraft:dead_tube_coral_fan[waterlogged=false]: minecraft:tube_coral_fan[waterlogged=false] # minecraft:dead_tube_coral_fan[waterlogged=true]: minecraft:tube_coral_fan[waterlogged=true] - # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=east] # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=north] # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=south] From 4126353a913a87891cc346c0dba352e4e3c223cc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 19:29:25 +0800 Subject: [PATCH 28/57] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=85=BC=E5=AE=B9leave?= =?UTF-8?q?s=E5=81=87=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mythicmobs/MythicItemDrop.java | 4 +- .../skript/condition/CondIsFurniture.java | 2 - .../skript/event/EvtCustomBlock.java | 3 - .../skript/event/EvtCustomClick.java | 1 - .../skript/event/EvtCustomFurniture.java | 2 - .../bukkit/block/BlockEventListener.java | 9 +-- .../furniture/BukkitFurnitureManager.java | 11 ++-- .../bukkit/font/BukkitFontManager.java | 9 +-- .../item/listener/DebugStickListener.java | 3 +- .../item/listener/ItemEventListener.java | 13 ++-- .../item/recipe/RecipeEventListener.java | 11 ++-- .../bukkit/loot/BukkitVanillaLootManager.java | 3 +- .../bukkit/pack/BukkitPackManager.java | 3 +- .../bukkit/plugin/BukkitCraftEngine.java | 10 ++- .../command/feature/GetItemCommand.java | 1 - .../command/feature/GiveItemCommand.java | 1 - .../plugin/command/feature/TestCommand.java | 3 - .../plugin/network/BukkitNetworkManager.java | 59 +++++++++++++++--- .../minecraft/LeavesReflections.java | 49 +++++++++++++++ .../plugin/user/BukkitServerPlayer.java | 61 +++++++++++-------- .../plugin/user/FakeBukkitServerPlayer.java | 32 ++++++++++ .../bukkit/util/AdventureModeUtils.java | 2 +- .../bukkit/util/BlockStateUtils.java | 2 +- .../craftengine/bukkit/util/BlockTags.java | 2 +- .../bukkit/util/ComponentUtils.java | 2 +- .../bukkit/util/DamageCauseUtils.java | 2 +- .../bukkit/util/DirectionUtils.java | 2 +- .../bukkit/util/DummyListener.java | 6 ++ .../bukkit/util/EnchantmentUtils.java | 2 +- .../bukkit/util/EntityDataUtils.java | 2 +- .../craftengine/bukkit/util/EntityUtils.java | 2 +- .../craftengine/bukkit/util/EventUtils.java | 2 +- .../bukkit/util/ExplosionUtils.java | 2 +- .../craftengine/bukkit/util/FeatureUtils.java | 2 +- .../craftengine/bukkit/util/FluidUtils.java | 2 +- .../bukkit/util/InteractUtils.java | 2 +- .../bukkit/util/InventoryUtils.java | 2 +- .../craftengine/bukkit/util/ItemTags.java | 2 +- .../craftengine/bukkit/util/LightUtils.java | 2 +- .../bukkit/util/LocationUtils.java | 2 +- .../bukkit/util/MaterialUtils.java | 2 +- .../craftengine/bukkit/util/MirrorUtils.java | 2 +- .../bukkit/util/MobEffectUtils.java | 2 +- .../util/NoteBlockChainUpdateUtils.java | 2 +- .../bukkit/util/OptimizedReflections.java | 6 -- .../craftengine/bukkit/util/RecipeUtils.java | 7 --- .../bukkit/util/RegistryUtils.java | 2 +- .../bukkit/util/RotationUtils.java | 2 +- .../craftengine/bukkit/util/SoundUtils.java | 2 +- .../bukkit/util/StairsShapeUtils.java | 2 +- common-files/src/main/resources/mappings.yml | 2 +- .../core/plugin/network/NetWorkUser.java | 11 +++- .../craftengine/core/util/VersionHelper.java | 16 ++++- gradle.properties | 2 +- 54 files changed, 267 insertions(+), 125 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/LeavesReflections.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/FakeBukkitServerPlayer.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DummyListener.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/OptimizedReflections.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java index 8b151df79..634f341c2 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java @@ -9,7 +9,7 @@ import io.lumine.mythic.api.skills.SkillCaster; import io.lumine.mythic.bukkit.BukkitAdapter; import io.lumine.mythic.bukkit.adapters.BukkitItemStack; import io.lumine.mythic.core.drops.droppables.ItemDrop; -import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -38,7 +38,7 @@ public class MythicItemDrop extends ItemDrop implements IItemDrop { if (caster != null && caster.getEntity() instanceof AbstractPlayer abstractPlayer) { Entity bukkitEntity = abstractPlayer.getBukkitEntity(); if (bukkitEntity instanceof Player bukkitPlayer) { - var player = BukkitCraftEngine.instance().adapt(bukkitPlayer); + var player = BukkitAdaptors.adapt(bukkitPlayer); context = ItemBuildContext.of(player); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java index 287596ff4..96b57c2d5 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/condition/CondIsFurniture.java @@ -12,8 +12,6 @@ import org.bukkit.entity.Entity; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.function.Predicate; - public class CondIsFurniture extends Condition { public static void register() { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java index 14a2dbdd4..93174f608 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomBlock.java @@ -10,8 +10,6 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.registrations.EventValues; import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; -import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher; @@ -19,7 +17,6 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java index d9b04c7ab..86b66d401 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java @@ -11,7 +11,6 @@ import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.registrations.EventValues; import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UnsafeBlockStateMatcher; diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java index e45b73a54..2afbea401 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomFurniture.java @@ -8,8 +8,6 @@ import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptEvent; import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.registrations.EventValues; -import io.papermc.paper.event.player.PlayerTrackEntityEvent; -import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; import org.bukkit.Location; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 085c0059b..7052fc484 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.block; import io.papermc.paper.event.block.BlockBreakBlockEvent; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -56,7 +57,7 @@ public final class BlockEventListener implements Listener { public void onPlayerAttack(EntityDamageByEntityEvent event) { if (!VersionHelper.isOrAbove1_20_5()) { if (event.getDamager() instanceof Player player) { - BukkitServerPlayer serverPlayer = plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); serverPlayer.setClientSideCanBreakBlock(true); } } @@ -65,7 +66,7 @@ public final class BlockEventListener implements Listener { @EventHandler(ignoreCancelled = true) public void onPlaceBlock(BlockPlaceEvent event) { Player player = event.getPlayer(); - BukkitServerPlayer serverPlayer = plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); // send swing if player is clicking a replaceable block if (serverPlayer.shouldResendSwing()) { player.swingHand(event.getHand()); @@ -112,7 +113,7 @@ public final class BlockEventListener implements Listener { int stateId = BlockStateUtils.blockStateToId(blockState); Player player = event.getPlayer(); Location location = block.getLocation(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); net.momirealms.craftengine.core.world.World world = new BukkitWorld(player.getWorld()); WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); @@ -246,7 +247,7 @@ public final class BlockEventListener implements Listener { Location location = player.getLocation(); ImmutableBlockState state = optionalCustomState.get(); Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); - state.owner().value().execute(PlayerOptionalContext.of(this.plugin.adapt(player), ContextHolder.builder() + state.owner().value().execute(PlayerOptionalContext.of(BukkitAdaptors.adapt(player), ContextHolder.builder() .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(event.getWorld()), LocationUtils.toVec3d(location))) .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 798f5c105..d9fb9c01d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -1,11 +1,13 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -207,15 +209,16 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { BukkitFurniture furniture = addNewFurniture(display, customFurniture); furniture.initializeColliders(); for (Player player : display.getTrackedPlayers()) { - this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); - this.plugin.networkManager().sendPacket(this.plugin.adapt(player), furniture.spawnPacket(player)); + BukkitAdaptors.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); + this.plugin.networkManager().sendPacket(BukkitAdaptors.adapt(player), furniture.spawnPacket(player)); } } } else { BukkitFurniture furniture = addNewFurniture(display, customFurniture); for (Player player : display.getTrackedPlayers()) { - this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); - this.plugin.networkManager().sendPacket(this.plugin.adapt(player), furniture.spawnPacket(player)); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); + serverPlayer.entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); + this.plugin.networkManager().sendPacket(serverPlayer, furniture.spawnPacket(player)); } if (preventChange) { this.plugin.scheduler().sync().runLater(furniture::initializeColliders, 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java index 794c0e81a..f6304a758 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent; import io.papermc.paper.event.player.AsyncChatDecorateEvent; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections; import net.momirealms.craftengine.bukkit.util.ComponentUtils; @@ -143,7 +144,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { if (renameText == null || renameText.isEmpty()) return; Component itemName = Component.text(renameText); - EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, this.plugin.adapt(player), renameText); + EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, BukkitAdaptors.adapt(player), renameText); if (replaceProcessResult.changed()) { Item wrapped = this.plugin.itemManager().wrap(result); wrapped.customNameJson(AdventureHelper.componentToJson(replaceProcessResult.newText())); @@ -160,7 +161,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { JsonElement json = ComponentUtils.paperAdventureToJsonElement(lines.get(i)); if (json == null) continue; Component line = AdventureHelper.jsonElementToComponent(json); - EmojiComponentProcessResult result = replaceComponentEmoji(line, plugin.adapt(player)); + EmojiComponentProcessResult result = replaceComponentEmoji(line, BukkitAdaptors.adapt(player)); if (result.changed()) { try { PaperReflections.method$SignChangeEvent$line.invoke(event, i, ComponentUtils.jsonElementToPaperAdventure(AdventureHelper.componentToJsonElement(result.newText()))); @@ -191,7 +192,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { for (int i = 0; i < pages.size(); i++) { JsonElement json = ComponentUtils.paperAdventureToJsonElement(pages.get(i)); Component page = AdventureHelper.jsonElementToComponent(json); - EmojiComponentProcessResult result = replaceComponentEmoji(page, plugin.adapt(player)); + EmojiComponentProcessResult result = replaceComponentEmoji(page, BukkitAdaptors.adapt(player)); if (result.changed()) { changed = true; try { @@ -214,7 +215,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { Object originalMessage = PaperReflections.field$AsyncChatDecorateEvent$originalMessage.get(event); String rawJsonMessage = ComponentUtils.paperAdventureToJson(originalMessage); if (Config.allowEmojiChat()) { - EmojiTextProcessResult processResult = replaceJsonEmoji(rawJsonMessage, this.plugin.adapt(player)); + EmojiTextProcessResult processResult = replaceJsonEmoji(rawJsonMessage, BukkitAdaptors.adapt(player)); boolean hasChanged = processResult.replaced(); if (!player.hasPermission(FontManager.BYPASS_CHAT)) { IllegalCharacterProcessResult result = processIllegalCharacters(processResult.text()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index 26d9cb05a..8b8df50b4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item.listener; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -49,7 +50,7 @@ public class DebugStickListener implements Listener { Material material = itemInHand.getType(); if (material != Material.DEBUG_STICK) return; Player bukkitPlayer = event.getPlayer(); - BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer); + BukkitServerPlayer player = BukkitAdaptors.adapt(bukkitPlayer); if (!(player.canInstabuild() && player.hasPermission("minecraft.debugstick")) && !player.hasPermission("minecraft.debugstick.always")) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index ab5660c90..76f05c35a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item.listener; import io.papermc.paper.event.block.CompostItemEvent; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; import net.momirealms.craftengine.bukkit.item.BukkitCustomItem; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -69,7 +70,7 @@ public class ItemEventListener implements Listener { public void onInteractEntity(PlayerInteractEntityEvent event) { Player player = event.getPlayer(); Entity entity = event.getRightClicked(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; @@ -107,7 +108,7 @@ public class ItemEventListener implements Listener { return; } - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; // 如果本tick内主手已被处理,则不处理副手 @@ -349,7 +350,7 @@ public class ItemEventListener implements Listener { if (action != Action.RIGHT_CLICK_AIR && action != Action.LEFT_CLICK_AIR) return; Player player = event.getPlayer(); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); if (serverPlayer.isSpectatorMode()) return; // Gets the item in hand @@ -411,7 +412,7 @@ public class ItemEventListener implements Listener { } Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); CustomItem customItem = optionalCustomItem.get(); - PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() + PlayerOptionalContext context = PlayerOptionalContext.of(BukkitAdaptors.adapt(event.getPlayer()), ContextHolder.builder() .withParameter(DirectContextParameters.ITEM_IN_HAND, wrapped) .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) @@ -425,7 +426,7 @@ public class ItemEventListener implements Listener { if (replacement == null) { event.setReplacement(null); } else { - ItemStack replacementItem = this.plugin.itemManager().buildItemStack(replacement, this.plugin.adapt(event.getPlayer())); + ItemStack replacementItem = this.plugin.itemManager().buildItemStack(replacement, BukkitAdaptors.adapt(event.getPlayer())); event.setReplacement(replacementItem); } } @@ -516,7 +517,7 @@ public class ItemEventListener implements Listener { if (optionalCustomItem.isEmpty()) return; BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); if (customItem.clientItem() == FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) return; - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); if (serverPlayer == null) return; this.plugin.scheduler().sync().runDelayed(() -> { Object container = FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer.serverPlayer()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index eb1004ba3..5b6359d3f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item.recipe; import com.destroystokyo.paper.event.inventory.PrepareResultEvent; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -455,7 +456,7 @@ public class RecipeEventListener implements Listener { Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - if (finalCost >= maxRepairCost && !plugin.adapt(player).canInstabuild()) { + if (finalCost >= maxRepairCost && !BukkitAdaptors.adapt(player).canInstabuild()) { hasResult = false; } @@ -548,7 +549,7 @@ public class RecipeEventListener implements Listener { return; } Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - Item newItem = customItemOptional.get().buildItem(plugin.adapt(player)); + Item newItem = customItemOptional.get().buildItem(BukkitAdaptors.adapt(player)); newItem.maxDamage(max); newItem.damage(Math.max(max - finalDurability, 0)); inventory.setResult(newItem.getItem()); @@ -597,7 +598,7 @@ public class RecipeEventListener implements Listener { CraftingInput input = getCraftingInput(inventory); if (input == null) return; Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); inventory.setResult(craftingTableRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); } @@ -650,7 +651,7 @@ public class RecipeEventListener implements Listener { SmithingInput input = getSmithingInput(inventory); if (smithingTrimRecipe.matches(input)) { Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(BukkitAdaptors.adapt(player), ContextHolder.EMPTY)); event.setResult(result); } else { event.setResult(null); @@ -674,7 +675,7 @@ public class RecipeEventListener implements Listener { SmithingInput input = getSmithingInput(inventory); if (smithingTransformRecipe.matches(input)) { Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - ItemStack processed = smithingTransformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + ItemStack processed = smithingTransformRecipe.assemble(input, new ItemBuildContext(BukkitAdaptors.adapt(player), ContextHolder.EMPTY)); event.setResult(processed); } else { event.setResult(null); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 3aeeb074b..9dc95e83b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.loot; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -72,7 +73,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme BukkitServerPlayer optionalPlayer = null; if (VersionHelper.isOrAbove1_20_5()) { if (event.getDamageSource().getCausingEntity() instanceof Player player) { - optionalPlayer = this.plugin.adapt(player); + optionalPlayer = BukkitAdaptors.adapt(player); builder.withParameter(DirectContextParameters.PLAYER, optionalPlayer); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index 0cea939f3..0ce69f22c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.pack; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.event.AsyncResourcePackGenerateEvent; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand; @@ -43,7 +44,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) { - Player player = plugin.adapt(event.getPlayer()); + Player player = BukkitAdaptors.adapt(event.getPlayer()); this.sendResourcePack(player); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 3c87fe07c..6c882875a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -50,6 +50,7 @@ import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable; import java.io.*; @@ -58,7 +59,6 @@ import java.net.URLConnection; import java.nio.file.Path; import java.util.List; import java.util.Objects; -import java.util.Optional; @SuppressWarnings("unchecked") public class BukkitCraftEngine extends CraftEngine { @@ -363,11 +363,9 @@ public class BukkitCraftEngine extends CraftEngine { } } - public BukkitServerPlayer adapt(org.bukkit.entity.Player player) { - if (player == null) return null; - return Optional.ofNullable((BukkitServerPlayer) networkManager().getOnlineUser(player)).orElseGet( - () -> (BukkitServerPlayer) networkManager().getUser(player) - ); + public BukkitServerPlayer adapt(@NotNull org.bukkit.entity.Player player) { + Objects.requireNonNull(player, "player cannot be null"); + return (BukkitServerPlayer) networkManager().getOnlineUser(player); } public AntiGriefLib antiGriefProvider() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java index 4005e7e5d..4c9143aab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java @@ -4,7 +4,6 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.plugin.CraftEngine; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java index 430ee64be..6f546d394 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java @@ -28,7 +28,6 @@ import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; import java.util.Collection; -import java.util.Optional; import java.util.concurrent.CompletableFuture; public class GiveItemCommand extends BukkitCommandFeature { 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 161171c20..1f1a9d666 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.command.CommandSender; @@ -19,8 +18,6 @@ public class TestCommand extends BukkitCommandFeature { return builder .senderType(Player.class) .handler(context -> { - Player player = context.sender(); - player.sendMessage("客户端模组状态: " + BukkitNetworkManager.instance().getUser(player).clientModEnabled()); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 7b3928905..e98de26d8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -12,9 +12,11 @@ import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIdFinder; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.LeavesReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.LibraryReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.plugin.user.FakeBukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.CooldownData; @@ -142,6 +144,47 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to init server connection", e); } + // Inject Leaves bot list + if (VersionHelper.isLeaves()) { + this.injectLeavesBotList(); + } + } + + public static BukkitNetworkManager instance() { + return instance; + } + + public void addFakePlayer(Player player) { + FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin); + fakePlayer.setPlayer(player); + this.onlineUsers.put(player.getUniqueId(), fakePlayer); + this.resetUserArray(); + } + + public boolean removeFakePlayer(Player player) { + BukkitServerPlayer fakePlayer = this.onlineUsers.get(player.getUniqueId()); + if (!(fakePlayer instanceof FakeBukkitServerPlayer)) { + return false; + } + this.onlineUsers.remove(player.getUniqueId()); + this.resetUserArray(); + this.saveCooldown(player, fakePlayer.cooldown()); + return true; + } + + @SuppressWarnings("unchecked") + private void injectLeavesBotList() { + try { + Object botList = LeavesReflections.field$BotList$INSTANCE.get(null); + List bots = (List) LeavesReflections.field$BotList$bots.get(botList); + ListMonitor monitor = new ListMonitor<>(bots, + (bot) -> addFakePlayer(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(bot)), + (bot) -> removeFakePlayer(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(bot)) + ); + LeavesReflections.field$BotList$bots.set(botList, monitor); + } catch (ReflectiveOperationException e) { + this.plugin.logger().severe("Failed to inject leaves bot list"); + } } private void registerPacketHandlers() { @@ -203,10 +246,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket()); } - public static BukkitNetworkManager instance() { - return instance; - } - @EventHandler(priority = EventPriority.LOWEST) public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); @@ -215,10 +254,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes user.setPlayer(player); this.onlineUsers.put(player.getUniqueId(), user); this.resetUserArray(); + // folia在此tick每个玩家 if (VersionHelper.isFolia()) { player.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> user.tick(), - () -> { - }, 1, 1); + () -> {}, 1, 1); } } } @@ -282,7 +321,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } @Override - public NetWorkUser getUser(Channel channel) { + public NetWorkUser getUser(@NotNull Channel channel) { ChannelPipeline pipeline = channel.pipeline(); return this.users.get(pipeline); } @@ -298,14 +337,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return getChannel((Player) player.platformPlayer()); } + @Nullable public NetWorkUser getUser(Player player) { return getUser(getChannel(player)); } + @Nullable public NetWorkUser getOnlineUser(Player player) { return this.onlineUsers.get(player.getUniqueId()); } + // 当假人的时候channel为null + @NotNull public Channel getChannel(Player player) { return FastNMS.INSTANCE.field$Connection$channel( FastNMS.INSTANCE.field$ServerGamePacketListenerImpl$connection( @@ -318,6 +361,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately, Runnable sendListener) { + if (player.isFakePlayer()) return; if (immediately) { this.immediatePacketConsumer.accept(player.nettyChannel(), packet, sendListener); } else { @@ -327,6 +371,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately, Runnable sendListener) { + if (player.isFakePlayer()) return; if (immediately) { this.immediatePacketsConsumer.accept(player.nettyChannel(), packet, sendListener); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/LeavesReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/LeavesReflections.java new file mode 100644 index 000000000..b7b89995c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/LeavesReflections.java @@ -0,0 +1,49 @@ +package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; + +//import net.momirealms.craftengine.core.util.MiscUtils; +//import net.momirealms.craftengine.core.util.ReflectionUtils; +//import net.momirealms.craftengine.core.util.VersionHelper; +//import org.bukkit.event.HandlerList; +// +//import java.lang.reflect.Field; +//import java.util.Optional; + +import net.momirealms.craftengine.core.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.util.List; + +// TODO API 太新了需要1.21.8,目前先采用其他方式解决假人问题 +public final class LeavesReflections { + private LeavesReflections() {} + +// public static final Class clazz$BotJoinEvent = MiscUtils.requireNonNullIf(ReflectionUtils.getClazz("org.leavesmc.leaves.event.bot.BotJoinEvent"), VersionHelper.isLeaves()); +// +// public static final Class clazz$BotRemoveEvent = MiscUtils.requireNonNullIf(ReflectionUtils.getClazz("org.leavesmc.leaves.event.bot.BotRemoveEvent"), VersionHelper.isLeaves()); +// +// public static final Class clazz$BotEvent = MiscUtils.requireNonNullIf(ReflectionUtils.getClazz("org.leavesmc.leaves.event.bot.BotEvent"), VersionHelper.isLeaves()); +// +// public static final Class clazz$Bot = MiscUtils.requireNonNullIf(ReflectionUtils.getClazz("org.leavesmc.leaves.entity.bot.Bot"), VersionHelper.isLeaves()); +// +// public static final Field field$BotEvent$bot = Optional.ofNullable(clazz$BotEvent) +// .map(it -> ReflectionUtils.getDeclaredField(it, clazz$Bot, 0)) +// .orElse(null); +// +// public static final Field field$BotJoinEvent$handlers = Optional.ofNullable(clazz$BotJoinEvent) +// .map(it -> ReflectionUtils.getDeclaredField(it, HandlerList.class, 0)) +// .orElse(null); +// +// public static final Field field$BotRemoveEvent$handlers = Optional.ofNullable(clazz$BotRemoveEvent) +// .map(it -> ReflectionUtils.getDeclaredField(it, HandlerList.class, 0)) +// .orElse(null); + + + public static final Class clazz$ServerBot = ReflectionUtils.getClazz("org.leavesmc.leaves.bot.ServerBot"); + + // 注入BotList来实现全版本的监听 + public static final Class clazz$BotList = ReflectionUtils.getClazz("org.leavesmc.leaves.bot.BotList"); + + public static final Field field$BotList$INSTANCE = ReflectionUtils.getDeclaredField(clazz$BotList, clazz$BotList, 0); + + public static final Field field$BotList$bots = ReflectionUtils.getDeclaredField(clazz$BotList, List.class, 0); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 64f58fa0c..a56e78b01 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 @@ -112,14 +112,16 @@ public class BukkitServerPlayer extends Player { private final Map entityTypeView = new ConcurrentHashMap<>(); - public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { + public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) { this.channel = channel; this.plugin = plugin; - for (String name : channel.pipeline().names()) { - ChannelHandler handler = channel.pipeline().get(name); - if (NetworkReflections.clazz$Connection.isInstance(handler)) { - this.connection = handler; - break; + if (channel != null) { + for (String name : channel.pipeline().names()) { + ChannelHandler handler = channel.pipeline().get(name); + if (NetworkReflections.clazz$Connection.isInstance(handler)) { + this.connection = handler; + break; + } } } } @@ -328,22 +330,37 @@ public class BukkitServerPlayer extends Player { } @Override - public void sendCustomPayload(Key channel, byte[] data) { + public void sendPackets(List packet, boolean immediately) { + this.plugin.networkManager().sendPackets(this, packet, immediately); + } + + @Override + public void sendPackets(List packet, boolean immediately, Runnable sendListener) { + this.plugin.networkManager().sendPackets(this, packet, immediately, sendListener); + } + + @Override + public void simulatePacket(Object packet) { + this.plugin.networkManager().simulatePacket(this, packet); + } + + @Override + public void sendCustomPayload(Key channelId, byte[] data) { try { - Object channelKey = KeyUtils.toResourceLocation(channel); + Object channelResourceLocation = KeyUtils.toResourceLocation(channelId); Object responsePacket; if (VersionHelper.isOrAbove1_20_2()) { Object dataPayload; if (NetworkReflections.clazz$UnknownPayload != null) { - dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelResourceLocation, Unpooled.wrappedBuffer(data)); } else if (DiscardedPayload.useNewMethod) { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data); + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelResourceLocation, data); } else { - dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data)); + dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelResourceLocation, Unpooled.wrappedBuffer(data)); } responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); } else { - responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelKey, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data))); + responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelResourceLocation, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data))); } this.sendPacket(responsePacket, true); } catch (Exception e) { @@ -365,21 +382,6 @@ public class BukkitServerPlayer extends Player { } } - @Override - public void sendPackets(List packet, boolean immediately) { - this.plugin.networkManager().sendPackets(this, packet, immediately); - } - - @Override - public void sendPackets(List packet, boolean immediately, Runnable sendListener) { - this.plugin.networkManager().sendPackets(this, packet, immediately, sendListener); - } - - @Override - public void simulatePacket(Object packet) { - this.plugin.networkManager().simulatePacket(this, packet); - } - @Override public ConnectionState decoderState() { return decoderState; @@ -861,6 +863,11 @@ public class BukkitServerPlayer extends Player { return this.connection; } + @Override + public boolean isFakePlayer() { + return false; + } + @Override public org.bukkit.entity.Player literalObject() { return platformPlayer(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/FakeBukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/FakeBukkitServerPlayer.java new file mode 100644 index 000000000..d4bef6ccf --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/FakeBukkitServerPlayer.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.bukkit.plugin.user; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; + +public class FakeBukkitServerPlayer extends BukkitServerPlayer { + + public FakeBukkitServerPlayer(BukkitCraftEngine plugin) { + super(plugin, null); + } + + @Override + public Channel nettyChannel() { + return null; + } + + @Override + public ChannelHandler connection() { + return null; + } + + @Override + public void kick(Component message) { + } + + @Override + public boolean isFakePlayer() { + return true; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/AdventureModeUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/AdventureModeUtils.java index c22eacf48..7204ad9a4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/AdventureModeUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/AdventureModeUtils.java @@ -10,7 +10,7 @@ import org.bukkit.Location; import org.bukkit.inventory.ItemStack; @SuppressWarnings("DuplicatedCode") -public class AdventureModeUtils { +public final class AdventureModeUtils { private AdventureModeUtils() {} 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 00c8dfc57..5728c14df 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 @@ -22,7 +22,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -public class BlockStateUtils { +public final class BlockStateUtils { public static final IdentityHashMap CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>(); private static int vanillaStateSize; private static boolean hasInit; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java index a83a91c27..4514ebc54 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.HashMap; import java.util.Map; -public class BlockTags { +public final class BlockTags { private static final Map CACHE = new HashMap<>(); private BlockTags() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java index 471d8eda5..70c2eba7c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ComponentUtils.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections; import net.momirealms.craftengine.core.util.AdventureHelper; -public class ComponentUtils { +public final class ComponentUtils { private ComponentUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java index 0f0c1be64..4e7ca0542 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.util.DamageSource; import org.bukkit.event.entity.EntityDamageEvent; -public class DamageCauseUtils { +public final class DamageCauseUtils { private DamageCauseUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java index 341e88c9d..cf0ef5d0c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.core.util.Direction; import org.bukkit.block.BlockFace; -public class DirectionUtils { +public final class DirectionUtils { private DirectionUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DummyListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DummyListener.java new file mode 100644 index 000000000..842b5d99b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DummyListener.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.bukkit.util; + +import org.bukkit.event.Listener; + +public class DummyListener implements Listener { +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java index 01bc7d699..6424b21f3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import java.util.HashMap; import java.util.Map; -public class EnchantmentUtils { +public final class EnchantmentUtils { private EnchantmentUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java index d2c342de1..f9eb22d2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.util.VersionHelper; -public class EntityDataUtils { +public final class EntityDataUtils { private EntityDataUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index a4b87cde2..41419ab9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -15,7 +15,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import java.util.function.Consumer; -public class EntityUtils { +public final class EntityUtils { private EntityUtils() { } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EventUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EventUtils.java index 2a09a636b..7be7e243f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EventUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EventUtils.java @@ -4,7 +4,7 @@ import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; -public class EventUtils { +public final class EventUtils { private EventUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ExplosionUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ExplosionUtils.java index 3d8de7149..3c45e46ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ExplosionUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ExplosionUtils.java @@ -5,7 +5,7 @@ import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent; @SuppressWarnings("UnstableApiUsage") -public class ExplosionUtils { +public final class ExplosionUtils { public static boolean isDroppingItems(BlockExplodeEvent event) { return event.getExplosionResult() != ExplosionResult.KEEP && event.getExplosionResult() != ExplosionResult.TRIGGER_BLOCK; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java index 6b6f53ea5..c81be9337 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.core.util.Key; -public class FeatureUtils { +public final class FeatureUtils { private FeatureUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java index 3af0cadc1..685d43961 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.world.FluidCollisionRule; import org.bukkit.FluidCollisionMode; -public class FluidUtils { +public final class FluidUtils { private FluidUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index 34c7cf27e..d16537def 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -36,7 +36,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -public class InteractUtils { +public final class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Map, Boolean>> ENTITY_INTERACTIONS = new HashMap<>(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java index 49192e90c..089f0b315 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java @@ -6,7 +6,7 @@ import org.bukkit.event.inventory.InventoryEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -public class InventoryUtils { +public final class InventoryUtils { private InventoryUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index e94bc4a32..55d2fa70c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.HashMap; import java.util.Map; -public class ItemTags { +public final class ItemTags { private static final Map CACHE = new HashMap<>(); public static final Key AXES = Key.of("minecraft:axes"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java index 51e046ddf..636c5c1e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java @@ -9,7 +9,7 @@ import java.util.BitSet; import java.util.List; import java.util.Map; -public class LightUtils { +public final class LightUtils { private LightUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index 5a103ac24..0d0688e1c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -9,7 +9,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.jetbrains.annotations.NotNull; -public class LocationUtils { +public final class LocationUtils { private LocationUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java index 0ef3c5caf..02db8aff7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java @@ -10,7 +10,7 @@ import java.util.Locale; import java.util.Objects; import java.util.Optional; -public class MaterialUtils { +public final class MaterialUtils { public static Material MACE; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java index 32e08ada7..df2c71bbc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.core.util.Mirror; -public class MirrorUtils { +public final class MirrorUtils { private MirrorUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MobEffectUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MobEffectUtils.java index b944a8b39..c1a6e36af 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MobEffectUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MobEffectUtils.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; -public class MobEffectUtils { +public final class MobEffectUtils { private MobEffectUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java index 3cb195fa0..b77fea1ba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; -public class NoteBlockChainUpdateUtils { +public final class NoteBlockChainUpdateUtils { private NoteBlockChainUpdateUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/OptimizedReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/OptimizedReflections.java deleted file mode 100644 index 211da4037..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/OptimizedReflections.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.momirealms.craftengine.bukkit.util; - -public class OptimizedReflections { - - -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java deleted file mode 100644 index ca67f6b6b..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RecipeUtils.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.bukkit.util; - -public class RecipeUtils { - - private RecipeUtils() {} - -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java index 0e53d5748..155385d6f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; -public class RegistryUtils { +public final class RegistryUtils { private RegistryUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java index 65f632d7a..3cda588f7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.core.util.Rotation; -public class RotationUtils { +public final class RotationUtils { private RotationUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java index 4f9ebf05b..9f21529df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import org.bukkit.SoundCategory; -public class SoundUtils { +public final class SoundUtils { private SoundUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java index c06c548b5..dde8b33f7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.core.block.state.properties.StairsShape; -public class StairsShapeUtils { +public final class StairsShapeUtils { private StairsShapeUtils() {} public static StairsShape fromNMSStairsShape(Object shape) { diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index daf22369a..d3f9f58f2 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -4323,7 +4323,7 @@ minecraft:heavy_weighted_pressure_plate[power=14]: minecraft:heavy_weighted_pres minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pressure_plate[power=1] #### Corals #### -# # Coral blocks are ideal for creating water blocks or wall-mounted blocks. But you have to sacrifice its dry appearance. +# Coral blocks are ideal for creating water blocks or wall-mounted blocks. But you have to sacrifice its dry appearance. # minecraft:dead_brain_coral[waterlogged=false]: minecraft:brain_coral[waterlogged=false] # minecraft:dead_brain_coral[waterlogged=true]: minecraft:brain_coral[waterlogged=true] # minecraft:dead_brain_coral_fan[waterlogged=false]: minecraft:brain_coral_fan[waterlogged=false] diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 042413ba9..453b8e055 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -6,6 +6,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.UUID; @@ -13,8 +14,16 @@ import java.util.UUID; public interface NetWorkUser { boolean isOnline(); + // 对假人来说会null + @Nullable Channel nettyChannel(); + // 对假人来说会null + @Nullable + ChannelHandler connection(); + + boolean isFakePlayer(); + Plugin plugin(); String name(); @@ -49,8 +58,6 @@ public interface NetWorkUser { Object platformPlayer(); - ChannelHandler connection(); - Map entityPacketHandlers(); boolean clientModEnabled(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java index 0c003a3eb..6b36f6bc3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java @@ -16,7 +16,7 @@ public class VersionHelper { private static final boolean mojmap; private static final boolean folia; private static final boolean paper; - + private static final boolean leaves; private static final boolean v1_20; private static final boolean v1_20_1; private static final boolean v1_20_2; @@ -77,6 +77,7 @@ public class VersionHelper { mojmap = checkMojMap(); folia = checkFolia(); paper = checkPaper(); + leaves = checkLeaves(); } catch (Exception e) { throw new RuntimeException("Failed to init VersionHelper", e); } @@ -150,6 +151,15 @@ public class VersionHelper { return false; } + private static boolean checkLeaves() { + try { + Class.forName("org.leavesmc.leaves.bot.ServerBot"); + return true; + } catch (ClassNotFoundException ignored) { + } + return false; + } + public static boolean isFolia() { return folia; } @@ -158,6 +168,10 @@ public class VersionHelper { return paper; } + public static boolean isLeaves() { + return leaves; + } + public static boolean isMojmap() { return mojmap; } diff --git a/gradle.properties b/gradle.properties index 199f62c5e..4d209dd7a 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.61.4 +project_version=0.0.61.5 config_version=43 lang_version=23 project_group=net.momirealms From 8ae2ad83e8830ceb9de0c1fcdc9a499af07bfac7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 21:11:24 +0800 Subject: [PATCH 29/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BApack.yml?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/pack/AbstractPackManager.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 714cc2f60..c8c09139c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -321,11 +321,15 @@ public abstract class AbstractPackManager implements PackManager { Yaml yaml = new Yaml(new StringKeyConstructor(path, new LoaderOptions())); try (InputStream is = Files.newInputStream(metaFile)) { Map data = yaml.load(is); - enable = ResourceConfigUtils.getAsBoolean(data.getOrDefault("enable", true), "enable"); - namespace = data.getOrDefault("namespace", namespace).toString(); - description = Optional.ofNullable(data.get("description")).map(String::valueOf).orElse(null); - version = Optional.ofNullable(data.get("version")).map(String::valueOf).orElse(null); - author = Optional.ofNullable(data.get("author")).map(String::valueOf).orElse(null); + if (data != null) { + enable = ResourceConfigUtils.getAsBoolean(data.getOrDefault("enable", true), "enable"); + namespace = data.getOrDefault("namespace", namespace).toString(); + description = Optional.ofNullable(data.get("description")).map(String::valueOf).orElse(null); + version = Optional.ofNullable(data.get("version")).map(String::valueOf).orElse(null); + author = Optional.ofNullable(data.get("author")).map(String::valueOf).orElse(null); + } else { + this.plugin.logger().warn("Failed to load resource meta file: " + metaFile); + } } catch (IOException e) { this.plugin.logger().warn("Failed to load " + metaFile, e); } From fee3d2f1ac4b69c3c77d890e4e5ad963ae070db8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 21:42:32 +0800 Subject: [PATCH 30/57] =?UTF-8?q?=E7=BA=A0=E6=AD=A3=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=8E=9F=E7=89=88=E7=89=A9=E5=93=81itemstack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/item/BukkitItemManager.java | 3 ++- .../bukkit/item/recipe/BukkitRecipeConvertor.java | 10 ---------- 2 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 39c1f336c..434b2d978 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -365,9 +365,10 @@ public class BukkitItemManager extends AbstractItemManager { return null; } + @Nullable private ItemStack createVanillaItemStack(Key id) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id)); - if (item == null) { + if (item == null || item == MItems.AIR) { return null; } return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(item, 1)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java deleted file mode 100644 index c899ca4df..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.momirealms.craftengine.bukkit.item.recipe; - -import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.util.Key; -import org.bukkit.inventory.ItemStack; - -public interface BukkitRecipeConvertor> { - - Runnable convert(Key id, T recipe); -} From 0ebbd5068ed871f264c83a3eb58e2510b32c5fbb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 21:42:49 +0800 Subject: [PATCH 31/57] Update BukkitItemManager.java --- .../momirealms/craftengine/bukkit/item/BukkitItemManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 434b2d978..ecd7cb499 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -368,7 +368,7 @@ public class BukkitItemManager extends AbstractItemManager { @Nullable private ItemStack createVanillaItemStack(Key id) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id)); - if (item == null || item == MItems.AIR) { + if (item == MItems.AIR) { return null; } return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(item, 1)); From 70b8cab05618eb00a3b4156b160508d6a0901ed1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 13 Aug 2025 21:56:08 +0800 Subject: [PATCH 32/57] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A9=BA=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/item/BukkitItemManager.java | 2 +- .../craftengine/core/item/AbstractCustomItem.java | 5 +++++ .../craftengine/core/item/BuildableItem.java | 2 ++ .../core/item/CloneableConstantItem.java | 5 +++++ .../core/item/recipe/AbstractRecipeSerializer.java | 13 +++++++------ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index ecd7cb499..19f69cfc5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -368,7 +368,7 @@ public class BukkitItemManager extends AbstractItemManager { @Nullable private ItemStack createVanillaItemStack(Key id) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id)); - if (item == MItems.AIR) { + if (item == MItems.AIR && !id.equals(ItemKeys.AIR)) { return null; } return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(item, 1)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index 66e6c4d53..336d4c1a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -101,4 +101,9 @@ public abstract class AbstractCustomItem implements CustomItem { public @NotNull List behaviors() { return this.behaviors; } + + @Override + public boolean isEmpty() { + return false; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java index 1d3db94da..4e996c007 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/BuildableItem.java @@ -10,6 +10,8 @@ public interface BuildableItem { Item buildItem(ItemBuildContext context, int count); + boolean isEmpty(); + default Item buildItem(Player player) { return buildItem(ItemBuildContext.of(player)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java index 639d8d137..5270fbc72 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CloneableConstantItem.java @@ -27,4 +27,9 @@ public class CloneableConstantItem implements BuildableItem { public I buildItemStack(ItemBuildContext context, int count) { return this.item.copyWithCount(count).getItem(); } + + @Override + public boolean isEmpty() { + return this.item.isEmpty(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 8e24da2b6..3087306b1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -1,9 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.item.CloneableConstantItem; -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemManager; +import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20; import net.momirealms.craftengine.core.item.recipe.reader.VanillaRecipeReader1_20_5; @@ -72,9 +69,13 @@ public abstract class AbstractRecipeSerializer> implement } String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(resultMap.get("id"), "warning.config.recipe.result.missing_id"); int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); + BuildableItem resultItem = (BuildableItem) CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow(() -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)); + if (resultItem.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id); + } List> processors = ResourceConfigUtils.parseConfigAsList(resultMap.get("post-processors"), PostProcessors::fromMap); - return (CustomRecipeResult) new CustomRecipeResult<>( - CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow(() -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), + return new CustomRecipeResult<>( + resultItem, count, processors.isEmpty() ? null : processors.toArray(new PostProcessor[0]) ); From 5ea84511e8759d1cdbe2fcff4597326b852fe769 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 14 Aug 2025 18:02:43 +0800 Subject: [PATCH 33/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=AF=E8=A6=86?= =?UTF-8?q?=E5=86=99lore=EF=BC=8C=E5=A2=9E=E5=BC=BA=E7=89=A9=E5=93=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E8=AF=BB=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 18 ++++++ .../bukkit/item/ComponentItemWrapper.java | 14 ++++ .../item/factory/BukkitItemFactory.java | 5 ++ .../factory/ComponentItemFactory1_20_5.java | 5 ++ .../bukkit/plugin/BukkitCraftEngine.java | 2 +- .../core/block/AbstractBlockManager.java | 55 ++++++++++++++++ .../craftengine/core/item/AbstractItem.java | 5 ++ .../core/item/AbstractItemManager.java | 7 +- .../craftengine/core/item/Item.java | 2 + .../craftengine/core/item/ItemFactory.java | 2 + .../core/item/modifier/ItemDataModifiers.java | 7 ++ .../lore/OverwritableLoreModifier.java | 64 +++++++++++++++++++ gradle.properties | 2 +- 13 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index cab845559..cc347e0bb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -47,6 +47,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.block.BlockType; import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -885,4 +886,21 @@ public final class BukkitBlockManager extends AbstractBlockManager { } } } + + @Override + protected int getBlockRegistryId(Key id) { + Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)); + return FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, block).orElseThrow(() -> new IllegalStateException("Block " + id + " not found")); + } + + @Override + protected boolean isVanillaBlock(Key id) { + if (!id.namespace().equals("minecraft")) { + return false; + } + if (id.value().equals("air")) { + return true; + } + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)) != MBlocks.AIR; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 680d5b8e5..6a5d6bab2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -12,9 +12,11 @@ import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import java.util.Objects; import java.util.Optional; public class ComponentItemWrapper implements ItemWrapper { @@ -104,6 +106,18 @@ public class ComponentItemWrapper implements ItemWrapper { return FastNMS.INSTANCE.method$ItemStack$hasComponent(getLiteralObject(), ensureDataComponentType(type)); } + public boolean hasNonDefaultComponent(Object type) { + if (VersionHelper.isOrAbove1_21_4()) { + return FastNMS.INSTANCE.method$ItemStack$hasNonDefaultComponent(getLiteralObject(), ensureDataComponentType(type)); + } else { + Object item = FastNMS.INSTANCE.method$ItemStack$getItem(this.getLiteralObject()); + Object componentMap = FastNMS.INSTANCE.method$Item$components(item); + Object componentType = ensureDataComponentType(type); + Object defaultComponent = FastNMS.INSTANCE.method$DataComponentMap$get(componentMap, componentType); + return !Objects.equals(defaultComponent, getComponentExact(componentType)); + } + } + public void setComponentExact(Object type, final Object value) { FastNMS.INSTANCE.method$ItemStack$setComponent(this.getLiteralObject(), ensureDataComponentType(type), value); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 19838cdc9..c8f760d99 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -165,6 +165,11 @@ public abstract class BukkitItemFactory> extend throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } + @Override + protected boolean hasNonDefaultComponent(W item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + @Override protected void setComponent(W item, Object type, Object value) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 3dfeab143..447500af0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -267,6 +267,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory section) { + if (isVanillaBlock(id)) { + parseVanillaBlock(pack, path, id, section); + } else { + // check duplicated config + if (AbstractBlockManager.this.byId.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.block.duplicate"); + } + parseCustomBlock(pack, path, id, section); + } + } + + private void parseVanillaBlock(Pack pack, Path path, Key id, Map section) { + Map settings = MiscUtils.castToMap(section.get("settings"), true); + if (settings != null) { + Object clientBoundTags = settings.get("client-bound-tags"); + if (clientBoundTags instanceof List list) { + List clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList(); + AbstractBlockManager.this.clientBoundTags.put(getBlockRegistryId(id), clientSideTags); + } + } + } + + private void parseCustomBlock(Pack pack, Path path, Key id, Map section) { + // 获取方块设置 + BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); + // + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 3f7a75d8f..5d5799233 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -371,6 +371,11 @@ public class AbstractItem, I> implements Item { return this.factory.hasComponent(this.item, type); } + @Override + public boolean hasNonDefaultComponent(Object type) { + return this.factory.hasNonDefaultComponent(this.item, type); + } + @Override public void removeComponent(Object type) { this.factory.removeComponent(this.item, type); 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 8e8b9e043..cd324882a 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 @@ -73,7 +73,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl for (Map.Entry dataEntry : dataSection.entrySet()) { Object value = dataEntry.getValue(); if (value == null) continue; - Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(dataEntry.getKey(), Key.DEFAULT_NAMESPACE))).ifPresent(factory -> { + String key = dataEntry.getKey(); + int idIndex = key.indexOf('#'); + if (idIndex != -1) { + key = key.substring(0, idIndex); + } + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(key, Key.DEFAULT_NAMESPACE))).ifPresent(factory -> { try { callback.accept((ItemDataModifier) factory.create(value)); } catch (LocalizedResourceConfigException e) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 69c9a68f8..8c48642be 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -163,6 +163,8 @@ public interface Item { boolean hasComponent(Object type); + boolean hasNonDefaultComponent(Object type); + void removeComponent(Object type); void setExactComponent(Object type, Object value); 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 43de1de6f..b2cac48ba 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 @@ -69,6 +69,8 @@ public abstract class ItemFactory, I> { protected abstract void resetComponent(W item, Object type); + protected abstract boolean hasNonDefaultComponent(W item, Object type); + protected abstract I getItem(W item); protected abstract void customModelData(W item, Integer data); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index f120401e8..7828a2dc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.item.modifier.lore.OverwritableLoreModifier; import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -40,10 +41,15 @@ public final class ItemDataModifiers { public static final Key LORE = Key.of("craftengine:lore"); public static final Key UNBREAKABLE = Key.of("craftengine:unbreakable"); public static final Key DYNAMIC_LORE = Key.of("craftengine:dynamic-lore"); + public static final Key OVERWRITABLE_LORE = Key.of("craftengine:overwritable-lore"); public static void register(Key key, ItemDataModifierFactory factory) { ((WritableRegistry>) BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY) .register(ResourceKey.create(Registries.ITEM_DATA_MODIFIER_FACTORY.location(), key), factory); + if (key.value().contains("-")) { + ((WritableRegistry>) BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY) + .register(ResourceKey.create(Registries.ITEM_DATA_MODIFIER_FACTORY.location(), new Key(key.namespace(), key.value().replace("-", "_"))), factory); + } } public static void init() {} @@ -52,6 +58,7 @@ public final class ItemDataModifiers { register(EXTERNAL, ExternalModifier.FACTORY); register(LORE, LoreModifier.FACTORY); register(DYNAMIC_LORE, DynamicLoreModifier.FACTORY); + register(OVERWRITABLE_LORE, OverwritableLoreModifier.FACTORY); register(DYED_COLOR, DyedColorModifier.FACTORY); register(TAGS, TagsModifier.FACTORY); register(NBT, TagsModifier.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java new file mode 100644 index 000000000..82c944859 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java @@ -0,0 +1,64 @@ +package net.momirealms.craftengine.core.item.modifier.lore; + +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.ItemDataModifierFactory; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifiers; +import net.momirealms.craftengine.core.item.modifier.SimpleNetworkItemDataModifier; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.CompoundTag; + +public final class OverwritableLoreModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); + private final LoreModifier loreModifier; + + public OverwritableLoreModifier(LoreModifier loreModifier) { + this.loreModifier = loreModifier; + } + + @Override + public Key type() { + return ItemDataModifiers.OVERWRITABLE_LORE; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { + return item; + } + return this.loreModifier.apply(item, context); + } + + @Override + public Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.LORE; + } + + @Override + public Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Lore"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.Lore"; + } + + public static class Factory implements ItemDataModifierFactory { + @Override + public ItemDataModifier create(Object arg) { + LoreModifier lore = LoreModifier.createLoreModifier(arg); + return new OverwritableLoreModifier<>(lore); + } + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { + return item; + } + return SimpleNetworkItemDataModifier.super.prepareNetworkItem(item, context, networkData); + } +} diff --git a/gradle.properties b/gradle.properties index 4d209dd7a..75cc0ec10 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.55 +nms_helper_version=1.0.56 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 9247dd3f948d91974076fbfad55f269ce1fcc8f2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 15 Aug 2025 17:21:46 +0800 Subject: [PATCH 34/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dclient-bound-model?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/item/AbstractItemManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 cd324882a..4b18d7194 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 @@ -326,7 +326,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl Key clientBoundMaterial = section.containsKey("client-bound-material") ? Key.from(section.get("client-bound-material").toString().toLowerCase(Locale.ENGLISH)) : material; // 如果是原版物品,那么custom-model-data只能是0,即使用户设置了其他值 int customModelData = isVanillaItem ? 0 : ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); - boolean clientBoundModel = section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-data"), "client-bound-data") : Config.globalClientboundModel(); + boolean clientBoundModel = section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel(); if (customModelData < 0) { throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); } @@ -374,8 +374,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } catch (LocalizedResourceConfigException e) { collector.add(e); } + // 应用客户端侧数据 try { - applyDataModifiers(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + if (VersionHelper.PREMIUM) { + applyDataModifiers(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + } } catch (LocalizedResourceConfigException e) { collector.add(e); } From fe3dd8ae9d8a45320c2209a25eb32bd72c037e59 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 15 Aug 2025 17:21:58 +0800 Subject: [PATCH 35/57] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc76894ba..10bf509de 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre ## Differences Between Versions | Version | Official Support | Max Players | Dev Builds | |-------------------|------------------|-------------|------------| -| Community Edition | ❌ No | 20 | ❌ No | +| Community Edition | ❌ No | 30 | ❌ No | | Premium Edition | ✔️ Yes | Unlimited | ✔️ Yes | ### 💖 Support the Developer From d89c7c530509b7c268248964b20d5aafe2b5e516 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 16 Aug 2025 01:45:48 +0800 Subject: [PATCH 36/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=AF=E8=A6=86?= =?UTF-8?q?=E5=86=99=E7=89=A9=E5=93=81=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/modifier/ItemDataModifiers.java | 2 + .../OverwritableItemNameModifier.java | 60 +++++++++++++++++++ .../lore/OverwritableLoreModifier.java | 21 +++++-- 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemNameModifier.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index 7828a2dc8..cbb6436e4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -32,6 +32,7 @@ public final class ItemDataModifiers { public static final Key ATTRIBUTES = Key.of("craftengine:attributes"); public static final Key ARGUMENTS = Key.of("craftengine:arguments"); public static final Key ITEM_NAME = Key.of("craftengine:item-name"); + public static final Key OVERWRITABLE_ITEM_NAME = Key.of("craftengine:overwritable-item-name"); public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable"); public static final Key REMOVE_COMPONENTS = Key.of("craftengine:remove-components"); public static final Key TAGS = Key.of("craftengine:tags"); @@ -71,6 +72,7 @@ public final class ItemDataModifiers { register(TRIM, TrimModifier.FACTORY); register(HIDE_TOOLTIP, HideTooltipModifier.FACTORY); register(ARGUMENTS, ArgumentsModifier.FACTORY); + register(OVERWRITABLE_ITEM_NAME, OverwritableItemNameModifier.FACTORY); if (VersionHelper.isOrAbove1_20_5()) { register(CUSTOM_NAME, CustomNameModifier.FACTORY); register(ITEM_NAME, ItemNameModifier.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemNameModifier.java new file mode 100644 index 000000000..979e70716 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemNameModifier.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.Nullable; + +public class OverwritableItemNameModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); + private final ItemNameModifier modifier; + + public OverwritableItemNameModifier(String argument) { + this.modifier = new ItemNameModifier<>(argument); + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (VersionHelper.COMPONENT_RELEASE) { + if (item.hasNonDefaultComponent(ComponentKeys.ITEM_NAME)) { + return item; + } + } else { + if (item.hasTag("display", "Name")) { + return item; + } + } + return this.modifier.apply(item, context); + } + + @Override + public Key type() { + return ItemDataModifiers.OVERWRITABLE_ITEM_NAME; + } + + @Override + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return ComponentKeys.ITEM_NAME; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"display", "Name"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "display.Name"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + return new OverwritableItemNameModifier<>(arg.toString()); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java index 82c944859..624eaf279 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/lore/OverwritableLoreModifier.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifiers; import net.momirealms.craftengine.core.item.modifier.SimpleNetworkItemDataModifier; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; public final class OverwritableLoreModifier implements SimpleNetworkItemDataModifier { @@ -25,8 +26,14 @@ public final class OverwritableLoreModifier implements SimpleNetworkItemDataM @Override public Item apply(Item item, ItemBuildContext context) { - if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { - return item; + if (VersionHelper.COMPONENT_RELEASE) { + if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { + return item; + } + } else { + if (item.hasTag("display", "Lore")) { + return item; + } } return this.loreModifier.apply(item, context); } @@ -56,8 +63,14 @@ public final class OverwritableLoreModifier implements SimpleNetworkItemDataM @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { - return item; + if (VersionHelper.COMPONENT_RELEASE) { + if (item.hasNonDefaultComponent(ComponentKeys.LORE)) { + return item; + } + } else { + if (item.hasTag("display", "Lore")) { + return item; + } } return SimpleNetworkItemDataModifier.super.prepareNetworkItem(item, context, networkData); } From 4e90278cd90d7710db93779228a3496558fee98f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 16 Aug 2025 17:27:02 +0800 Subject: [PATCH 37/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=BB=E9=80=A0?= =?UTF-8?q?=E5=90=8E=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/recipe/CustomSmithingTransformRecipe.java | 6 ++++-- gradle.properties | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index dd3d7920d..bbb5aed75 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -99,8 +99,10 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip if (this.mergeComponents) { finalResult = base.mergeCopy(wrappedResult); } - for (ItemDataProcessor processor : this.processors) { - processor.accept(base, wrappedResult, finalResult); + if (this.processors != null) { + for (ItemDataProcessor processor : this.processors) { + processor.accept(base, wrappedResult, finalResult); + } } return finalResult.getItem(); } diff --git a/gradle.properties b/gradle.properties index 75cc0ec10..4cece09ea 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.61.5 +project_version=0.0.61.6 config_version=43 lang_version=23 project_group=net.momirealms From e7ca6a8a3c1ebf7ca0d629eabdaf6f93b7d23194 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 16 Aug 2025 20:15:17 +0800 Subject: [PATCH 38/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=A5=E9=87=8D?= =?UTF-8?q?=E7=9A=84=E5=8F=91=E5=8C=85=E7=89=A9=E5=93=81=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 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 1b69dbc5d..0e0a6236d 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 @@ -2241,7 +2241,7 @@ public class PacketConsumers { // 因为不能走编码器只能替换对象 public static final TriConsumer CONTAINER_CLICK_1_21_5 = (user, event, packet) -> { try { - var player = (net.momirealms.craftengine.core.entity.player.Player) user; + BukkitServerPlayer player = (BukkitServerPlayer) user; int containerId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$containerId(packet); int stateId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$stateId(packet); short slotNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$slotNum(packet); diff --git a/gradle.properties b/gradle.properties index 4cece09ea..b3c3e3382 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.61.6 +project_version=0.0.61.7 config_version=43 lang_version=23 project_group=net.momirealms @@ -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.56 +nms_helper_version=1.0.57 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From fb6c8ba767b2f9f2979c8d2c581b3df17cea42ef Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 17 Aug 2025 09:06:39 +0800 Subject: [PATCH 39/57] =?UTF-8?q?feat(entity):=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=E6=9C=AB=E5=BD=B1=E4=BA=BA=E6=89=8B=E4=B8=8A?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/data/BlockDisplayEntityData.java | 2 +- .../bukkit/entity/data/EnderManData.java | 13 ++++ .../entity/data/ItemDisplayEntityData.java | 4 +- .../bukkit/entity/data/MonsterData.java | 8 ++ .../entity/data/TextDisplayEntityData.java | 10 +-- .../plugin/network/PacketConsumers.java | 1 + .../handler/EndermanPacketHandler.java | 77 +++++++++++++++++++ .../reflection/minecraft/MEntityTypes.java | 4 + .../bukkit/util/EntityDataUtils.java | 1 + 9 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EnderManData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/MonsterData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockDisplayEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockDisplayEntityData.java index 080480286..c4fa2a0d4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockDisplayEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockDisplayEntityData.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; public class BlockDisplayEntityData extends DisplayEntityData { // Block display only - public static final DisplayEntityData DisplayedBlock = new BlockDisplayEntityData<>(BlockDisplayEntityData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState); + public static final BlockDisplayEntityData DisplayedBlock = new BlockDisplayEntityData<>(BlockDisplayEntityData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState); public BlockDisplayEntityData(Class clazz, Object serializer, T defaultValue) { super(clazz, serializer, defaultValue); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EnderManData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EnderManData.java new file mode 100644 index 000000000..b09d5dcd5 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EnderManData.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import java.util.Optional; + +public class EnderManData extends MonsterData { + public static final EnderManData> CarryState = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$OPTIONAL_BLOCK_STATE, Optional.empty()); + public static final EnderManData Creepy = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$BOOLEAN, false); + public static final EnderManData StaredAt = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$BOOLEAN, false); + + public EnderManData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemDisplayEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemDisplayEntityData.java index 928881558..09d39ebdc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemDisplayEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemDisplayEntityData.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect public class ItemDisplayEntityData extends DisplayEntityData { // Item display only - public static final DisplayEntityData DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY); + public static final ItemDisplayEntityData DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY); /** * Display type: * 0 = NONE @@ -17,7 +17,7 @@ public class ItemDisplayEntityData extends DisplayEntityData { * 7 = GROUND * 8 = FIXED */ - public static final DisplayEntityData DisplayType = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0); + public static final ItemDisplayEntityData DisplayType = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0); public ItemDisplayEntityData(Class clazz, Object serializer, T defaultValue) { super(clazz, serializer, defaultValue); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/MonsterData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/MonsterData.java new file mode 100644 index 000000000..7817c7695 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/MonsterData.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +public class MonsterData extends PathfinderMobData { + + public MonsterData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java index 4919a8a41..73a801d3b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/TextDisplayEntityData.java @@ -3,11 +3,11 @@ package net.momirealms.craftengine.bukkit.entity.data; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; public class TextDisplayEntityData extends DisplayEntityData { - public static final DisplayEntityData Text = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$COMPONENT, CoreReflections.instance$Component$empty); - public static final DisplayEntityData LineWidth = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 200); - public static final DisplayEntityData BackgroundColor = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 0x40000000); - public static final DisplayEntityData TextOpacity = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) -1); - public static final DisplayEntityData TextDisplayMasks = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0); + public static final TextDisplayEntityData Text = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$COMPONENT, CoreReflections.instance$Component$empty); + public static final TextDisplayEntityData LineWidth = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 200); + public static final TextDisplayEntityData BackgroundColor = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 0x40000000); + public static final TextDisplayEntityData TextOpacity = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) -1); + public static final TextDisplayEntityData TextDisplayMasks = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0); public TextDisplayEntityData(Class clazz, Object serializer, T defaultValue) { super(clazz, serializer, defaultValue); 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 0e0a6236d..211574a66 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 @@ -137,6 +137,7 @@ public class PacketConsumers { ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java new file mode 100644 index 000000000..2588803f4 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java @@ -0,0 +1,77 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class EndermanPacketHandler implements EntityPacketHandler { + public static final EndermanPacketHandler INSTANCE = new EndermanPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.ENDERMAN_OPTIONAL_BLOCK_STATE) { + @SuppressWarnings("unchecked") + Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (blockState.isEmpty()) continue; + int stateId = BlockStateUtils.blockStateToId(blockState.get()); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = PacketConsumers.remap(stateId); + } else { + newStateId = PacketConsumers.remapMOD(stateId); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(BlockStateUtils.idToBlockState(newStateId)) + )); + isChanged = true; + } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) + )); + isChanged = true; + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java index ef5ab374d..8674fbf23 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java @@ -58,6 +58,8 @@ public final class MEntityTypes { public static final int HAPPY_GHAST$registryId; public static final Object PLAYER; public static final int PLAYER$registryId; + public static final Object ENDERMAN; + public static final int ENDERMAN$registryId; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -122,5 +124,7 @@ public final class MEntityTypes { ARROW$registryId = getRegistryId(ARROW); SPECTRAL_ARROW = getById("spectral_arrow"); SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW); + ENDERMAN = getById("enderman"); + ENDERMAN$registryId = getRegistryId(ENDERMAN); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java index f9eb22d2e..f495b0291 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java @@ -17,6 +17,7 @@ public final class EntityDataUtils { public static final int CUSTOM_NAME_DATA_ID = 2; public static final int ITEM_DATA_ID = 8; public static final int ITEM_FRAME_DATA_ID = VersionHelper.isOrAbove1_21_6() ? 9 : 8; + public static final int ENDERMAN_OPTIONAL_BLOCK_STATE = 16; public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) { int bitMask = 0; From d1a3442ae6936ca5a5051115d3781e94e14285f0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 17 Aug 2025 10:51:27 +0800 Subject: [PATCH 40/57] =?UTF-8?q?feat(entity):=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E5=90=AB=E6=9C=89=E6=96=B9=E5=9D=97=E7=8A=B6=E6=80=81=E7=9A=84?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E5=A4=84=E7=90=86=E5=B9=B6=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/data/AbstractMinecartData.java | 26 ++++ .../entity/data/BlockAttachedEntityData.java | 8 ++ .../bukkit/entity/data/GlowItemFrameData.java | 8 ++ .../bukkit/entity/data/HangingEntityData.java | 18 +++ .../bukkit/entity/data/ItemFrameData.java | 12 ++ .../bukkit/entity/data/PrimedTntData.java | 19 +++ .../bukkit/entity/data/VehicleEntityData.java | 11 ++ .../plugin/network/PacketConsumers.java | 15 ++- .../AbstractMinecartPacketHandler.java | 114 ++++++++++++++++++ .../handler/ArmorStandPacketHandler.java | 4 +- .../handler/BlockDisplayPacketHandler.java | 8 +- .../handler/CommonItemPacketHandler.java | 2 +- .../handler/EndermanPacketHandler.java | 8 +- .../handler/ItemDisplayPacketHandler.java | 4 +- .../handler/ItemFramePacketHandler.java | 4 +- .../handler/PrimedTNTPacketHandler.java | 77 ++++++++++++ .../handler/TextDisplayPacketHandler.java | 4 +- .../plugin/reflection/minecraft/MBlocks.java | 4 + .../reflection/minecraft/MEntityTypes.java | 32 +++++ .../bukkit/util/EntityDataUtils.java | 10 +- 20 files changed, 363 insertions(+), 25 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/AbstractMinecartData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockAttachedEntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/GlowItemFrameData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/HangingEntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemFrameData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/PrimedTntData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/VehicleEntityData.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/AbstractMinecartPacketHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/AbstractMinecartData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/AbstractMinecartData.java new file mode 100644 index 000000000..c0b8a6202 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/AbstractMinecartData.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.Optional; + +public class AbstractMinecartData extends VehicleEntityData { + // 1.20~1.21.2 + public static final AbstractMinecartData DisplayBlock = of(AbstractMinecartData.class, EntityDataValue.Serializers$INT, BlockStateUtils.blockStateToId(MBlocks.AIR$defaultState), !VersionHelper.isOrAbove1_21_3()); + // 1.21.3+ + public static final AbstractMinecartData> CustomDisplayBlock = of(AbstractMinecartData.class, EntityDataValue.Serializers$OPTIONAL_BLOCK_STATE, Optional.empty(), VersionHelper.isOrAbove1_21_3()); + public static final AbstractMinecartData DisplayOffset = of(AbstractMinecartData.class, EntityDataValue.Serializers$INT, 6, true); + // 1.20~1.21.2 + public static final AbstractMinecartData CustomDisplay = of(AbstractMinecartData.class, EntityDataValue.Serializers$BOOLEAN, false, !VersionHelper.isOrAbove1_21_3()); + + public static AbstractMinecartData of(final Class clazz, final Object serializer, T defaultValue, boolean condition) { + if (!condition) return null; + return new AbstractMinecartData<>(clazz, serializer, defaultValue); + } + + public AbstractMinecartData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockAttachedEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockAttachedEntityData.java new file mode 100644 index 000000000..0eca0b855 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BlockAttachedEntityData.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +public class BlockAttachedEntityData extends BaseEntityData { + + public BlockAttachedEntityData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/GlowItemFrameData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/GlowItemFrameData.java new file mode 100644 index 000000000..43c76d481 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/GlowItemFrameData.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +public class GlowItemFrameData extends ItemFrameData { + + public GlowItemFrameData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/HangingEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/HangingEntityData.java new file mode 100644 index 000000000..52124ab39 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/HangingEntityData.java @@ -0,0 +1,18 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.util.VersionHelper; + +public class HangingEntityData extends BlockAttachedEntityData { + // 1.21.6+ + public static final HangingEntityData Direction = of(HangingEntityData.class, EntityDataValue.Serializers$DIRECTION, CoreReflections.instance$Direction$SOUTH, VersionHelper.isOrAbove1_21_6()); + + public static HangingEntityData of(final Class clazz, final Object serializer, T defaultValue, boolean condition) { + if (!condition) return null; + return new HangingEntityData<>(clazz, serializer, defaultValue); + } + + public HangingEntityData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemFrameData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemFrameData.java new file mode 100644 index 000000000..295de9eda --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/ItemFrameData.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; + +public class ItemFrameData extends HangingEntityData { + public static final ItemFrameData Item = new ItemFrameData<>(ItemFrameData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY); + public static final ItemFrameData Rotation = new ItemFrameData<>(ItemFrameData.class, EntityDataValue.Serializers$INT, 0); + + public ItemFrameData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/PrimedTntData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/PrimedTntData.java new file mode 100644 index 000000000..1a37bba1a --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/PrimedTntData.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.core.util.VersionHelper; + +public class PrimedTntData extends BaseEntityData { + public static final PrimedTntData Fuse = of(PrimedTntData.class, EntityDataValue.Serializers$INT, 80, true); + // 1.20.3+ + public static final PrimedTntData BlockState = of(PrimedTntData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.TNT$defaultState, VersionHelper.isOrAbove1_20_3()); + + public static PrimedTntData of(final Class clazz, final Object serializer, T defaultValue, boolean condition) { + if (!condition) return null; + return new PrimedTntData<>(clazz, serializer, defaultValue); + } + + public PrimedTntData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/VehicleEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/VehicleEntityData.java new file mode 100644 index 000000000..435173b3f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/VehicleEntityData.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.bukkit.entity.data; + +public class VehicleEntityData extends BaseEntityData { + public static final VehicleEntityData Hurt = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$INT, 0); + public static final VehicleEntityData HurtDir = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$INT, 1); + public static final VehicleEntityData Damage = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$FLOAT, 0.0F); + + public VehicleEntityData(Class clazz, Object serializer, T defaultValue) { + super(clazz, serializer, defaultValue); + } +} 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 211574a66..36a23762e 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 @@ -18,6 +18,7 @@ import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; @@ -138,6 +139,13 @@ public class PacketConsumers { ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); @@ -150,6 +158,9 @@ public class PacketConsumers { ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false); ADD_ENTITY_HANDLERS[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); ADD_ENTITY_HANDLERS[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); + if (VersionHelper.isOrAbove1_20_3()) { + ADD_ENTITY_HANDLERS[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE); + } if (VersionHelper.isOrAbove1_20_5()) { ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); } @@ -237,10 +248,12 @@ public class PacketConsumers { } public static int remap(int stateId) { + // if (true) return 0; return mappings[stateId]; } public static int remapMOD(int stateId) { + // if (true) return 0; return mappingsMOD[stateId]; } @@ -1946,7 +1959,7 @@ public class PacketConsumers { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue; + if (entityDataId != BaseEntityData.CustomName.id()) continue; Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (optionalTextComponent.isEmpty()) continue; Object textComponent = optionalTextComponent.get(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/AbstractMinecartPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/AbstractMinecartPacketHandler.java new file mode 100644 index 000000000..7e087f395 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/AbstractMinecartPacketHandler.java @@ -0,0 +1,114 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.AbstractMinecartData; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class AbstractMinecartPacketHandler implements EntityPacketHandler { + public static final AbstractMinecartPacketHandler INSTANCE = new AbstractMinecartPacketHandler(); + private static final BlockStateHandler HANDLER = VersionHelper.isOrAbove1_21_3() ? BlockStateHandler_1_21_3.INSTANCE : BlockStateHandler_1_20.INSTANCE; + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + Object blockState = HANDLER.handle(user, packedItem, entityDataId); + if (blockState != null) { + packedItems.set(i, blockState); + isChanged = true; + } else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) { + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) + )); + isChanged = true; + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } + + interface BlockStateHandler { + Object handle(NetWorkUser user, Object packedItem, int entityDataId); + } + + static class BlockStateHandler_1_21_3 implements BlockStateHandler { + protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_21_3(); + + @Override + public Object handle(NetWorkUser user, Object packedItem, int entityDataId) { + if (entityDataId != AbstractMinecartData.CustomDisplayBlock.id()) return null; + @SuppressWarnings("unchecked") + Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (blockState.isEmpty()) return null; + int stateId = BlockStateUtils.blockStateToId(blockState.get()); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = PacketConsumers.remap(stateId); + } else { + newStateId = PacketConsumers.remapMOD(stateId); + } + if (newStateId == stateId) return null; + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(BlockStateUtils.idToBlockState(newStateId)) + ); + } + } + + static class BlockStateHandler_1_20 implements BlockStateHandler { + protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_20(); + + @Override + public Object handle(NetWorkUser user, Object packedItem, int entityDataId) { + if (entityDataId != AbstractMinecartData.DisplayBlock.id()) return null; + int stateId = (int) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = PacketConsumers.remap(stateId); + } else { + newStateId = PacketConsumers.remapMOD(stateId); + } + if (newStateId == stateId) return null; + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, newStateId); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java index c36ef9352..d7aa19418 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; @@ -32,7 +32,7 @@ public class ArmorStandPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue; + if (entityDataId != BaseEntityData.CustomName.id()) continue; @SuppressWarnings("unchecked") Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (optionalTextComponent.isEmpty()) continue; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java index 207cd4842..3f9d13d5d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; @@ -30,7 +31,7 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.BLOCK_STATE_DATA_ID) { + if (entityDataId == BlockDisplayEntityData.DisplayedBlock.id()) { Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); int stateId = BlockStateUtils.blockStateToId(blockState); int newStateId; @@ -39,12 +40,13 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler { } else { newStateId = PacketConsumers.remapMOD(stateId); } + if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) )); isChanged = true; - } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { + } else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) { @SuppressWarnings("unchecked") Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (optionalTextComponent.isEmpty()) continue; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java index 7e60b7671..17bba65f8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -28,7 +28,7 @@ public class CommonItemPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.ITEM_DATA_ID) continue; + if (entityDataId != EntityDataUtils.UNSAFE_ITEM_DATA_ID) continue; Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { long time = System.currentTimeMillis(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java index 2588803f4..2d1f7f43a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.data.EnderManData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; @@ -30,7 +31,7 @@ public class EndermanPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.ENDERMAN_OPTIONAL_BLOCK_STATE) { + if (entityDataId == EnderManData.CarryState.id()) { @SuppressWarnings("unchecked") Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (blockState.isEmpty()) continue; @@ -41,12 +42,13 @@ public class EndermanPacketHandler implements EntityPacketHandler { } else { newStateId = PacketConsumers.remapMOD(stateId); } + if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( entityDataId, serializer, Optional.of(BlockStateUtils.idToBlockState(newStateId)) )); isChanged = true; - } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { + } else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) { @SuppressWarnings("unchecked") Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (optionalTextComponent.isEmpty()) continue; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java index 911e661e3..77dff78ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; +import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; @@ -25,7 +25,7 @@ public class ItemDisplayPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.DISPLAYED_ITEM_DATA_ID) continue; + if (entityDataId != ItemDisplayEntityData.DisplayedItem.id()) continue; Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java index 1c75b767f..25c4f3871 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java @@ -1,10 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; +import net.momirealms.craftengine.bukkit.entity.data.ItemFrameData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; @@ -28,7 +28,7 @@ public class ItemFramePacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.ITEM_FRAME_DATA_ID) continue; + if (entityDataId != ItemFrameData.Item.id()) continue; Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { long time = System.currentTimeMillis(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java new file mode 100644 index 000000000..8e377fb95 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java @@ -0,0 +1,77 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData; +import net.momirealms.craftengine.bukkit.entity.data.PrimedTntData; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class PrimedTNTPacketHandler implements EntityPacketHandler { + public static final PrimedTNTPacketHandler INSTANCE = new PrimedTNTPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == PrimedTntData.BlockState.id()) { + Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + int stateId = BlockStateUtils.blockStateToId(blockState); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = PacketConsumers.remap(stateId); + } else { + newStateId = PacketConsumers.remapMOD(stateId); + } + if (newStateId == stateId) continue; + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) + )); + isChanged = true; + } else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) { + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); + } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) + )); + isChanged = true; + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java index a9cea9178..a02346b58 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java @@ -1,10 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.TextDisplayEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; @@ -31,7 +31,7 @@ public class TextDisplayPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != EntityDataUtils.TEXT_DATA_ID) continue; + if (entityDataId != TextDisplayEntityData.Text.id()) continue; Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (textComponent == CoreReflections.instance$Component$empty) break; String json = ComponentUtils.minecraftToJson(textComponent); 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 5255de607..d8971adba 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 @@ -20,6 +20,8 @@ public final class MBlocks { public static final Object SNOW; public static final Object WATER; public static final Object WATER$defaultState; + public static final Object TNT; + public static final Object TNT$defaultState; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -41,5 +43,7 @@ public final class MBlocks { SNOW = getById("snow"); WATER = getById("water"); WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); + TNT = getById("tnt"); + TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java index 8674fbf23..726d54947 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java @@ -60,6 +60,22 @@ public final class MEntityTypes { public static final int PLAYER$registryId; public static final Object ENDERMAN; public static final int ENDERMAN$registryId; + public static final Object TNT; + public static final int TNT$registryId; + public static final Object CHEST_MINECART; + public static final int CHEST_MINECART$registryId; + public static final Object COMMAND_BLOCK_MINECART; + public static final int COMMAND_BLOCK_MINECART$registryId; + public static final Object FURNACE_MINECART; + public static final int FURNACE_MINECART$registryId; + public static final Object HOPPER_MINECART; + public static final int HOPPER_MINECART$registryId; + public static final Object MINECART; + public static final int MINECART$registryId; + public static final Object SPAWNER_MINECART; + public static final int SPAWNER_MINECART$registryId; + public static final Object TNT_MINECART; + public static final int TNT_MINECART$registryId; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -126,5 +142,21 @@ public final class MEntityTypes { SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW); ENDERMAN = getById("enderman"); ENDERMAN$registryId = getRegistryId(ENDERMAN); + TNT = getById("tnt"); + TNT$registryId = getRegistryId(TNT); + CHEST_MINECART = getById("chest_minecart"); + CHEST_MINECART$registryId = getRegistryId(CHEST_MINECART); + COMMAND_BLOCK_MINECART = getById("command_block_minecart"); + COMMAND_BLOCK_MINECART$registryId = getRegistryId(COMMAND_BLOCK_MINECART); + FURNACE_MINECART = getById("furnace_minecart"); + FURNACE_MINECART$registryId = getRegistryId(FURNACE_MINECART); + HOPPER_MINECART = getById("hopper_minecart"); + HOPPER_MINECART$registryId = getRegistryId(HOPPER_MINECART); + MINECART = getById("minecart"); + MINECART$registryId = getRegistryId(MINECART); + SPAWNER_MINECART = getById("spawner_minecart"); + SPAWNER_MINECART$registryId = getRegistryId(SPAWNER_MINECART); + TNT_MINECART = getById("tnt_minecart"); + TNT_MINECART$registryId = getRegistryId(TNT_MINECART); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java index f495b0291..1f03ba9ed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.bukkit.util; -import net.momirealms.craftengine.core.util.VersionHelper; - public final class EntityDataUtils { private EntityDataUtils() {} @@ -11,13 +9,7 @@ public final class EntityDataUtils { private static final int USE_DEFAULT_BACKGROUND = 0x04; // 4 private static final int LEFT_ALIGNMENT = 0x08; // 8 private static final int RIGHT_ALIGNMENT = 0x10; // 16 - public static final int BLOCK_STATE_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; - public static final int TEXT_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; - public static final int DISPLAYED_ITEM_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; - public static final int CUSTOM_NAME_DATA_ID = 2; - public static final int ITEM_DATA_ID = 8; - public static final int ITEM_FRAME_DATA_ID = VersionHelper.isOrAbove1_21_6() ? 9 : 8; - public static final int ENDERMAN_OPTIONAL_BLOCK_STATE = 16; + public static final int UNSAFE_ITEM_DATA_ID = 8; // 正常来说应该通过定义 Data 获取 id 这样的做法未经验证可能不安全 public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) { int bitMask = 0; From afddac910aec6ee3703d815e09afce7850c3d78b Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 17 Aug 2025 12:06:13 +0800 Subject: [PATCH 41/57] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=B5=8B=E8=AF=95=E5=91=BD=E4=BB=A4=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=B5=8B=E8=AF=95=E7=9F=BF=E8=BD=A6=E4=B8=8A=E5=B8=A6?= =?UTF-8?q?=E6=9C=89=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E6=96=B9=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 因为minecraft的data命令限制只能通过插件实现 --- .../plugin/command/feature/TestCommand.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 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 1f1a9d666..68d4037be 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,11 +1,26 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.parser.BlockStateParser; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; +import org.bukkit.entity.Minecart; +import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.parser.location.LocationParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.StringParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; public class TestCommand extends BukkitCommandFeature { @@ -16,8 +31,20 @@ public class TestCommand extends BukkitCommandFeature { @Override public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .senderType(Player.class) + .required("location", LocationParser.locationParser()) + .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(BlockStateParser.fillSuggestions(input.input(), input.cursor()).stream().map(Suggestion::suggestion).collect(Collectors.toList())); + } + })) .handler(context -> { + String data = context.get("id"); + Location location = context.get("location"); + ImmutableBlockState state = BlockStateParser.deserialize(data); + if (state == null) return; + Minecart minecart = location.getWorld().spawn(location, Minecart.class); + minecart.setDisplayBlockData(BlockStateUtils.fromBlockData(state.customBlockState().handle())); }); } From 90d67b09aad3a7e750165bdc23260a17310ec0ca Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 17 Aug 2025 17:51:57 +0800 Subject: [PATCH 42/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=89=A9=E5=93=81?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E5=92=8C=E6=8F=8F=E8=BF=B0=E7=9A=84=E9=A2=84?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 9 +- .../plugin/injector/WorldStorageInjector.java | 3 +- .../plugin/user/BukkitServerPlayer.java | 1 + common-files/src/main/resources/config.yml | 4 +- .../src/main/resources/translations/de.yml | 1 - .../src/main/resources/translations/en.yml | 1 - .../src/main/resources/translations/es.yml | 1 - .../src/main/resources/translations/ru_ru.yml | 1 - .../src/main/resources/translations/tr.yml | 1 - .../src/main/resources/translations/zh_cn.yml | 1 - .../core/block/AbstractBlockManager.java | 167 +++++++++++++++++- .../item/modifier/CustomNameModifier.java | 5 +- .../core/item/modifier/ItemDataModifiers.java | 2 +- .../core/item/modifier/ItemNameModifier.java | 5 +- .../item/modifier/lore/LoreModification.java | 8 +- .../core/item/modifier/lore/LoreModifier.java | 10 +- .../text/minimessage/FormattedLine.java | 75 ++++++++ 17 files changed, 271 insertions(+), 24 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/FormattedLine.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index cc347e0bb..47d6cf89e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -47,7 +47,6 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; -import org.bukkit.block.BlockType; import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -80,9 +79,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { private Map stateId2BlockHolder; // This map is used to change the block states that are not necessarily needed into a certain block state private Map blockAppearanceMapper; - // Used to automatically arrange block states for strings such as minecraft:note_block:0 - private Map> blockAppearanceArranger; - private Map> realBlockArranger; // Record the amount of real blocks by block type private Map registeredRealBlockSlots; // A set of blocks that sounds have been removed @@ -125,6 +121,11 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.resetPacketConsumers(); } + @Override + public String stateRegistryIdToStateSNBT(int id) { + return BlockStateUtils.idToBlockState(id).toString(); + } + public static BukkitBlockManager instance() { return instance; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index ce3a33ac8..1fdc089d0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -177,7 +177,6 @@ public final class WorldStorageInjector { return section; } - public static class SetBlockStateInterceptor { public static final SetBlockStateInterceptor INSTANCE = new SetBlockStateInterceptor(); @@ -215,7 +214,7 @@ public final class WorldStorageInjector { } } - protected static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) { + private static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) { try { Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(newState); CESection section = holder.ceSection(); 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 a56e78b01..523e9cd92 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 @@ -188,6 +188,7 @@ public class BukkitServerPlayer extends Player { }; } + @SuppressWarnings("UnstableApiUsage") @Override public void setGameMode(GameMode gameMode) { platformPlayer().setGameMode(Objects.requireNonNull(org.bukkit.GameMode.getByValue(gameMode.id()))); diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 66e7060f0..2d4cc5ea7 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -380,10 +380,10 @@ chunk-system: compression-method: 4 # Settings for injection injection: - # Requires a restart to apply + # Requires a restart to apply. # SECTION: Inject the LevelChunkSection # PALETTE: Inject the PalettedContainer - target: SECTION + target: PALETTE # 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: true diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 3cbda8827..3e4619163 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -239,7 +239,6 @@ warning.config.block.state.unavailable_vanilla: "Problem in Datei Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Blockzustand '', der den verfügbaren Slot-Bereich '0~' überschreitet." warning.config.block.state.conflict: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Blockzustand '', der bereits von '' belegt ist." warning.config.block.state.bind_failed: "Problem in Datei gefunden - Der Block '' konnte den echten Blockzustand für '' nicht binden, da der Zustand von '' belegt ist." -warning.config.block.state.missing_model: "Problem in Datei gefunden - Dem Block '' fehlt das erforderliche 'model' oder 'models'-Argument." warning.config.block.state.invalid_real_id: "Problem in Datei gefunden - Der Block '' verwendet einen echten Blockzustand '', der den verfügbaren Slot-Bereich '0~' überschreitet. Erwägen Sie, weitere echte Zustände in 'additional-real-blocks.yml' hinzuzufügen, wenn die Slots aufgebraucht sind." warning.config.block.state.model.missing_path: "Problem in Datei gefunden - Dem Block '' fehlt die erforderliche 'path'-Option für 'model'." warning.config.block.state.model.invalid_path: "Problem in Datei gefunden - Der Block '' hat ein 'path'-Argument '', das illegale Zeichen enthält. Bitte lesen Sie https://minecraft.wiki/w/Resource_location#Legal_characters." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index dc3cdb95c..6244a83e1 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -261,7 +261,6 @@ warning.config.block.state.unavailable_vanilla: "Issue found in file Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." warning.config.block.state.bind_failed: "Issue found in file - The block '' failed to bind real block state for '' as the state has been occupied by ''." -warning.config.block.state.missing_model: "Issue found in file - The block '' is missing the required 'model' or 'models' argument." warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." warning.config.block.state.model.missing_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_path: "Issue found in file - The block '' has a 'path' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 4306e0579..b26e3f80d 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -187,7 +187,6 @@ warning.config.block.state.unavailable_vanilla: "Problema encontrado en warning.config.block.state.invalid_vanilla_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que excede el rango de slots disponible '0~'." warning.config.block.state.conflict: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que está ocupado por ''." warning.config.block.state.bind_failed: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." -warning.config.block.state.missing_model: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'model' o 'models'." warning.config.block.state.invalid_real_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque real '' que excede el rango de slots disponible '0~'. Si los slots están usados, considera agregar más estados reales a 'additional-real-blocks.yml'." warning.config.block.state.model.missing_path: "Problema encontrado en el archivo - El bloque '' carece de la opción requerida 'path' para 'model'." warning.config.block.state.model.invalid_path: "Problema encontrado en el archivo - El bloque '' tiene un argumento 'path' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index 626e314d6..60036cb99 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -237,7 +237,6 @@ warning.config.block.state.unavailable_vanilla: "Проблема най warning.config.block.state.invalid_vanilla_id: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '', что превышает доступный диапазон слотов '0~'." warning.config.block.state.conflict: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '' которое занято ''." warning.config.block.state.bind_failed: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." -warning.config.block.state.missing_model: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'model' или 'models' аргумент." warning.config.block.state.invalid_real_id: "Проблема найдена в файле - Блок '' использует реальное состояние блока '', которое превышает доступный диапазон слотов '0~'. Рассмотрите возможность добавления большего количества реальных состояний в 'additional-real-blocks.yml' если слоты израсходованы." warning.config.block.state.model.missing_path: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'path' опция для 'model'." warning.config.block.state.model.invalid_path: "Проблема найдена в файле - Блок '' имеет 'path' аргумент '' содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index b1d73071c..0704fb7f2 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -185,7 +185,6 @@ warning.config.block.state.unavailable_vanilla: " dosyasında sor warning.config.block.state.invalid_vanilla_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir vanilya blok durumu '' kullanıyor." warning.config.block.state.conflict: " dosyasında sorun bulundu - '' bloğu, '' tarafından işgal edilmiş bir vanilya blok durumu '' kullanıyor." warning.config.block.state.bind_failed: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." -warning.config.block.state.missing_model: " dosyasında sorun bulundu - '' bloğu gerekli 'model' veya 'models' argümanı eksik." warning.config.block.state.invalid_real_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir gerçek blok durumu '' kullanıyor. Yuvalar kullanılmışsa, 'additional-real-blocks.yml' dosyasına daha fazla gerçek durum eklemeyi düşünün." warning.config.block.state.model.missing_path: " dosyasında sorun bulundu - '' bloğu, 'model' için gerekli 'path' seçeneği eksik." warning.config.block.state.model.invalid_path: " dosyasında sorun bulundu - '' bloğunun, yasak karakterler içeren bir 'path' argümanı '' var. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index da8ae3198..93b136d5a 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -261,7 +261,6 @@ warning.config.block.state.unavailable_vanilla: "在文件 发 warning.config.block.state.invalid_vanilla_id: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 超出可用槽位范围 '0~'" warning.config.block.state.conflict: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 已被 '' 占用" warning.config.block.state.bind_failed: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 因该状态已被 '' 占用" -warning.config.block.state.missing_model: "在文件 发现问题 - 方块 '' 缺少必需的 'model' 或 'models' 参数" warning.config.block.state.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 additional-real-blocks.yml 中添加更多真实状态" warning.config.block.state.model.missing_path: "在文件 发现问题 - 方块 '' 的 'model' 缺少必需的 'path' 选项" warning.config.block.state.model.invalid_path: "在文件 发现问题 - 方块 '' 的 'path' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 36862c946..70dfad312 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -1,18 +1,24 @@ package net.momirealms.craftengine.core.block; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.momirealms.craftengine.core.block.properties.Properties; +import net.momirealms.craftengine.core.block.properties.Property; 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.model.generation.AbstractModelGenerator; +import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; @@ -41,6 +47,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // client side block tags protected Map> clientBoundTags = Map.of(); protected Map> previousClientBoundTags = Map.of(); + // Used to automatically arrange block states for strings such as minecraft:note_block:0 + protected Map> blockAppearanceArranger; + protected Map> realBlockArranger; protected AbstractBlockManager(CraftEngine plugin) { super(plugin); @@ -139,6 +148,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected abstract int getBlockRegistryId(Key id); + public abstract String stateRegistryIdToStateSNBT(int id); + public class BlockParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; @@ -179,7 +190,161 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem private void parseCustomBlock(Pack pack, Path path, Key id, Map section) { // 获取方块设置 BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); - // + // 读取基础外观配置 + Map> properties; + Map appearances; + Map variants; + // 读取states区域 + Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow( + ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); + boolean singleState = !stateSection.containsKey("properties"); + // 单方块状态 + if (singleState) { + int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow( + stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); + // 获取原版外观的注册表id + int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow( + stateSection.get("state"), "warning.config.block.state.missing_state")); + // 为原版外观赋予外观模型并检查模型冲突 + this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(stateSection, "model", "models")); + // 设置参数 + properties = Map.of(); + appearances = Map.of("", appearanceId); + variants = Map.of("", new BlockStateVariant("", settings, internalId)); + } + // 多方块状态 + else { + properties = parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); + appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances")); + + } + } + + private Map parseBlockAppearances(Map appearancesSection) { + Map appearances = new HashMap<>(); + for (Map.Entry entry : appearancesSection.entrySet()) { + Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow( + appearanceSection.get("state"), "warning.config.block.state.missing_state")); + this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(appearanceSection, "model", "models")); + appearances.put(entry.getKey(), appearanceId); + } + return appearances; + } + + @NotNull + private Map> parseBlockProperties(Map propertiesSection) { + Map> properties = new HashMap<>(); + for (Map.Entry entry : propertiesSection.entrySet()) { + Property property = Properties.fromMap(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey())); + properties.put(entry.getKey(), property); + } + return properties; + } + + private void arrangeModelForStateAndVerify(int registryId, Object modelOrModels) { + // 如果没有配置models + if (modelOrModels == null) { + return; + } + // 获取variants + List variants; + if (modelOrModels instanceof String model) { + JsonObject json = new JsonObject(); + json.addProperty("model", model); + variants = Collections.singletonList(json); + } else { + variants = ResourceConfigUtils.parseConfigAsList(modelOrModels, this::parseAppearanceModelSectionAsJson); + if (variants.isEmpty()) { + return; + } + } + // 拆分方块id与属性 + String blockState = stateRegistryIdToStateSNBT(registryId); + Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); + String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); + // 结合variants + JsonElement combinedVariant = GsonHelper.combine(variants); + JsonElement previous = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant); + if (previous != null && !previous.equals(combinedVariant)) { + // todo 播报可能的冲突 + plugin.logger().warn("warning 1"); + } + } + + private JsonObject parseAppearanceModelSectionAsJson(Map section) { + JsonObject json = new JsonObject(); + String modelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("path"), "warning.config.block.state.model.missing_path"); + if (!ResourceLocation.isValid(modelPath)) { + throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath); + } + json.addProperty("model", modelPath); + if (section.containsKey("x")) + json.addProperty("x", ResourceConfigUtils.getAsInt(section.get("x"), "x")); + if (section.containsKey("y")) + json.addProperty("y", ResourceConfigUtils.getAsInt(section.get("y"), "y")); + if (section.containsKey("uvlock")) json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(section.get("uvlock"), "uvlock")); + if (section.containsKey("weight")) + json.addProperty("weight", ResourceConfigUtils.getAsInt(section.get("weight"), "weight")); + Map generationMap = MiscUtils.castToMap(section.get("generation"), true); + if (generationMap != null) { + prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap)); + } + return json; + } + + // 从方块外观的state里获取其原版方块的state id + private int pluginFormattedBlockStateToRegistryId(String blockState) { + // 五种合理情况 + // minecraft:note_block:10 + // note_block:10 + // minecraft:note_block[xxx=xxx] + // note_block[xxx=xxx] + // minecraft:barrier + String[] split = blockState.split(":", 3); + if (split.length >= 4) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); + } + int registryId; + String stateOrId = split[split.length - 1]; + boolean isId = false; + int arrangerIndex = 0; + try { + arrangerIndex = Integer.parseInt(stateOrId); + if (arrangerIndex < 0) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); + } + isId = true; + } catch (NumberFormatException ignored) { + } + // 如果末尾是id,则至少长度为2 + if (isId) { + if (split.length == 1) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); + } + // 获取原版方块的id + Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]); + try { + List arranger = blockAppearanceArranger.get(block); + if (arranger == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState); + } + if (arrangerIndex >= arranger.size()) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla_id", blockState, String.valueOf(arranger.size() - 1)); + } + registryId = arranger.get(arrangerIndex); + } catch (NumberFormatException e) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", e, blockState); + } + } else { + // 其他情况则是完整的方块 + BlockStateWrapper packedBlockState = createPackedBlockState(blockState); + if (packedBlockState == null || !packedBlockState.isVanillaBlock()) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); + } + registryId = packedBlockState.registryId(); + } + return registryId; } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index 8989c2225..4d4aaa318 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.text.minimessage.FormattedLine; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -12,6 +13,7 @@ import org.jetbrains.annotations.Nullable; public class CustomNameModifier implements SimpleNetworkItemDataModifier { public static final Factory FACTORY = new Factory<>(); private final String argument; + private final FormattedLine line; public CustomNameModifier(String argument) { if (Config.addNonItalicTag()) { @@ -23,6 +25,7 @@ public class CustomNameModifier implements SimpleNetworkItemDataModifier { } else { this.argument = argument; } + this.line = FormattedLine.create(this.argument); } public String customName() { @@ -36,7 +39,7 @@ public class CustomNameModifier implements SimpleNetworkItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - item.customNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); + item.customNameComponent(this.line.parse(context)); return item; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index cbb6436e4..d2eb6a9c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; -import net.momirealms.craftengine.core.item.modifier.lore.OverwritableLoreModifier; import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier; import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier; +import net.momirealms.craftengine.core.item.modifier.lore.OverwritableLoreModifier; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index 20728b979..fefb4696d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -4,6 +4,7 @@ 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.ItemDataModifierFactory; +import net.momirealms.craftengine.core.plugin.text.minimessage.FormattedLine; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -11,9 +12,11 @@ import org.jetbrains.annotations.Nullable; public class ItemNameModifier implements SimpleNetworkItemDataModifier { public static final Factory FACTORY = new Factory<>(); private final String argument; + private final FormattedLine line; public ItemNameModifier(String argument) { this.argument = argument; + this.line = FormattedLine.create(argument); } public String itemName() { @@ -27,7 +30,7 @@ public class ItemNameModifier implements SimpleNetworkItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - item.itemNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); + item.itemNameComponent(this.line.parse(context)); return item; } 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 index 0b6b8ce34..d033da602 100644 --- 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 @@ -2,28 +2,28 @@ 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.plugin.text.minimessage.FormattedLine; 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 record LoreModification(Operation operation, boolean split, FormattedLine[] 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())); + Stream parsed = Arrays.stream(this.content).map(line -> line.parse(context)); return this.split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed; } public List parseAsList(ItemBuildContext context) { - return this.parseAsStream(context).collect(Collectors.toList()); + return this.parseAsStream(context).toList(); } public enum Operation { 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 6e5f3411a..2068fbcc9 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 @@ -8,6 +8,8 @@ import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifiers; import net.momirealms.craftengine.core.item.modifier.SimpleNetworkItemDataModifier; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.text.minimessage.FormattedLine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -63,7 +65,9 @@ public sealed interface LoreModifier extends SimpleNetworkItemDataModifier rawLore[i] = o.toString(); } } - return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, rawLore)); + return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, + Arrays.stream(rawLore).map(line -> Config.addNonItalicTag() ? FormattedLine.create("" + line) : FormattedLine.create(line)) + .toArray(FormattedLine[]::new))); } List modifications = new ArrayList<>(rawLoreData.size() + 1); @@ -74,7 +78,9 @@ public sealed interface LoreModifier extends SimpleNetworkItemDataModifier 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.add(new LoreModificationHolder(new LoreModification(operation, split, + Arrays.stream(content).map(line -> Config.addNonItalicTag() ? FormattedLine.create("" + line) : FormattedLine.create(line)) + .toArray(FormattedLine[]::new)), lastPriority)); } } modifications.sort(LoreModificationHolder::compareTo); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/FormattedLine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/FormattedLine.java new file mode 100644 index 000000000..a5a2b6d20 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/FormattedLine.java @@ -0,0 +1,75 @@ +package net.momirealms.craftengine.core.plugin.text.minimessage; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.Context; +import net.kyori.adventure.text.minimessage.ParsingException; +import net.kyori.adventure.text.minimessage.tag.Tag; +import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.momirealms.craftengine.core.util.AdventureHelper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface FormattedLine { + TagResolver[] CUSTOM_RESOLVERS = new TagResolver[]{ + createDummyResolvers("expr"), + createDummyResolvers("image"), + createDummyResolvers("arg"), + createDummyResolvers("shift"), + createDummyResolvers("i18n"), + createDummyResolvers("global"), + createDummyResolvers("papi"), + createDummyResolvers("rel_papi") + }; + + Component parse(net.momirealms.craftengine.core.plugin.context.Context context); + + private static TagResolver createDummyResolvers(String tag) { + return new TagResolver() { + @Override + public boolean has(@NotNull String name) { + return tag.equals(name); + } + + @Override + public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + return null; + } + }; + } + + static FormattedLine create(String line) { + if (line.equals(AdventureHelper.customMiniMessage().stripTags(line, CUSTOM_RESOLVERS))) { + return new PreParsedLine(AdventureHelper.miniMessage().deserialize(line)); + } else { + return new DynamicLine(line); + } + } + + class PreParsedLine implements FormattedLine { + private final Component parsed; + + public PreParsedLine(Component parsed) { + this.parsed = parsed; + } + + @Override + public Component parse(net.momirealms.craftengine.core.plugin.context.Context context) { + return this.parsed; + } + } + + class DynamicLine implements FormattedLine { + private final String content; + + public DynamicLine(String content) { + this.content = content; + } + + @Override + public Component parse(net.momirealms.craftengine.core.plugin.context.Context context) { + return AdventureHelper.miniMessage().deserialize(this.content, context.tagResolvers()); + } + } +} + From 8aca3448d1488ab94b36ab7982857a58215b6b21 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 17 Aug 2025 18:41:50 +0800 Subject: [PATCH 43/57] =?UTF-8?q?=E7=95=A5=E5=BE=AE=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/command/feature/TestCommand.java | 1 - .../plugin/network/handler/PrimedTNTPacketHandler.java | 1 - .../core/item/modifier/CustomNameModifier.java | 1 - .../craftengine/core/item/modifier/ItemNameModifier.java | 1 - .../java/net/momirealms/craftengine/core/util/Key.java | 5 ++++- .../net/momirealms/craftengine/core/world/ChunkPos.java | 8 ++++---- .../core/world/chunk/storage/CachedStorage.java | 3 ++- 7 files changed, 10 insertions(+), 10 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 68d4037be..4c404b53f 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 @@ -6,7 +6,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.parser.BlockStateParser; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Minecart; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java index 8e377fb95..f352c9620 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; -import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData; import net.momirealms.craftengine.bukkit.entity.data.PrimedTntData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index 4d4aaa318..26c2ddbd3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -6,7 +6,6 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.text.minimessage.FormattedLine; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index fefb4696d..cc36ef68d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.text.minimessage.FormattedLine; -import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java index 6ec44fbc6..16594275a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java @@ -49,6 +49,9 @@ public record Key(String namespace, String value) { if (obj == null) { return false; } + if (obj == this) { + return true; + } if (!(obj instanceof Key key)) return false; // 先比value命中率高 return this.value.equals(key.value()) && this.namespace.equals(key.namespace()); @@ -56,7 +59,7 @@ public record Key(String namespace, String value) { @Override public @NotNull String toString() { - return this.namespace + ":" + this.value; + return asString(); } public String asString() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java b/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java index 115dd689a..a053afd79 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/ChunkPos.java @@ -71,14 +71,14 @@ public class ChunkPos { @Override public final boolean equals(Object o) { + if (o == null) return false; + if (o == this) return true; if (!(o instanceof ChunkPos chunkPos)) return false; - return x == chunkPos.x && z == chunkPos.z; + return this.longKey == chunkPos.longKey; } @Override public int hashCode() { - int result = x; - result = 31 * result + z; - return result; + return Long.hashCode(this.longKey); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java index 9cc9d5d5e..23fd7cd94 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CachedStorage.java @@ -21,7 +21,8 @@ public class CachedStorage implements WorldDataStora this.chunkCache = Caffeine.newBuilder() .executor(CraftEngine.instance().scheduler().async()) .scheduler(Scheduler.systemScheduler()) - .expireAfterAccess(30, TimeUnit.SECONDS) + .initialCapacity(2048) + .expireAfterAccess(60, TimeUnit.SECONDS) .build(); } From 69b9b164c9c5e1cdc5b908a64af6206c7c60180f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 17 Aug 2025 19:26:05 +0800 Subject: [PATCH 44/57] Update PacketConsumers.java --- .../plugin/network/PacketConsumers.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 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 36a23762e..8d9028a65 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 @@ -87,8 +87,8 @@ import java.util.function.BiConsumer; public class PacketConsumers { private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; - private static int[] mappings; - private static int[] mappingsMOD; + private static int[] BLOCK_STATE_MAPPINGS; + private static int[] MOD_BLOCK_STATE_MAPPINGS; private static IntIdentityList BLOCK_LIST; private static IntIdentityList BIOME_LIST; @@ -227,34 +227,34 @@ public class PacketConsumers { } public static void initBlocks(Map map, int registrySize) { - mappings = new int[registrySize]; + int[] newMappings = new int[registrySize]; for (int i = 0; i < registrySize; i++) { - mappings[i] = i; + newMappings[i] = i; } - mappingsMOD = Arrays.copyOf(mappings, registrySize); + int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); for (Map.Entry entry : map.entrySet()) { - mappings[entry.getKey()] = entry.getValue(); + newMappings[entry.getKey()] = entry.getValue(); if (BlockStateUtils.isVanillaBlock(entry.getKey())) { - mappingsMOD[entry.getKey()] = entry.getValue(); + newMappingsMOD[entry.getKey()] = entry.getValue(); } } - for (int i = 0; i < mappingsMOD.length; i++) { + for (int i = 0; i < newMappingsMOD.length; i++) { if (BlockStateUtils.isVanillaBlock(i)) { - mappingsMOD[i] = remap(i); + newMappingsMOD[i] = newMappings[i]; } } + BLOCK_STATE_MAPPINGS = newMappings; + MOD_BLOCK_STATE_MAPPINGS = newMappingsMOD; BLOCK_LIST = new IntIdentityList(registrySize); BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); } public static int remap(int stateId) { - // if (true) return 0; - return mappings[stateId]; + return BLOCK_STATE_MAPPINGS[stateId]; } public static int remapMOD(int stateId) { - // if (true) return 0; - return mappingsMOD[stateId]; + return MOD_BLOCK_STATE_MAPPINGS[stateId]; } public static final BiConsumer LEVEL_CHUNK_WITH_LIGHT = (user, event) -> { From b7586310f967773f5835413310fa4667537688b7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 17 Aug 2025 22:44:12 +0800 Subject: [PATCH 45/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=89=A9=E5=93=81?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitCustomItem.java | 15 ++++- .../bukkit/item/BukkitItemManager.java | 2 +- .../item/listener/ItemEventListener.java | 56 +++++++++++++++- common-files/src/main/resources/config.yml | 10 ++- .../src/main/resources/translations/en.yml | 3 + .../src/main/resources/translations/zh_cn.yml | 3 + .../core/item/AbstractCustomItem.java | 11 ++- .../core/item/AbstractItemManager.java | 37 ++++++++++ .../craftengine/core/item/CustomItem.java | 6 ++ .../craftengine/core/item/ItemManager.java | 4 ++ .../core/item/modifier/ArgumentsModifier.java | 2 +- .../core/item/modifier/ItemDataModifiers.java | 1 + .../item/modifier/ItemVersionModifier.java | 40 +++++++++++ .../core/item/updater/ItemUpdateConfig.java | 67 +++++++++++++++++++ .../core/item/updater/ItemUpdateResult.java | 6 ++ .../core/item/updater/ItemUpdater.java | 9 +++ .../core/item/updater/ItemUpdaterType.java | 10 +++ .../core/item/updater/ItemUpdaters.java | 42 ++++++++++++ .../item/updater/impl/ApplyDataOperation.java | 49 ++++++++++++++ .../item/updater/impl/ResetOperation.java | 63 +++++++++++++++++ .../item/updater/impl/TransmuteOperation.java | 32 +++++++++ .../core/plugin/config/Config.java | 24 +++++++ .../core/registry/BuiltInRegistries.java | 2 + .../craftengine/core/registry/Registries.java | 2 + .../core/world/chunk/SingularPalette.java | 2 +- gradle.properties | 6 +- 26 files changed, 492 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemVersionModifier.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateConfig.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateResult.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdater.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaterType.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaters.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ApplyDataOperation.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ResetOperation.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/TransmuteOperation.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 5bd11d54c..d58b647a9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.updater.ItemUpdateConfig; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -25,8 +26,9 @@ public class BukkitCustomItem extends AbstractCustomItem { List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, - Map>> events) { - super(isVanillaItem, id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events); + Map>> events, + ItemUpdateConfig updater) { + super(isVanillaItem, id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events, updater); this.item = item; this.clientItem = clientItem; } @@ -75,6 +77,7 @@ public class BukkitCustomItem extends AbstractCustomItem { private final List> modifiers = new ArrayList<>(4); private final List> clientBoundModifiers = new ArrayList<>(4); private ItemSettings settings; + private ItemUpdateConfig updater; public BuilderImpl(Object item, Object clientBoundItem) { this.item = item; @@ -153,12 +156,18 @@ public class BukkitCustomItem extends AbstractCustomItem { return this; } + @Override + public Builder updater(ItemUpdateConfig updater) { + this.updater = updater; + return this; + } + @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); this.clientBoundModifiers.addAll(this.settings.clientBoundModifiers()); return new BukkitCustomItem(this.isVanillaItem, this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors), - List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events); + List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events, updater); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 19f69cfc5..c21500bb8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -62,7 +62,7 @@ public class BukkitItemManager extends AbstractItemManager { instance = this; this.plugin = plugin; this.factory = BukkitItemFactory.create(plugin); - this.itemEventListener = new ItemEventListener(plugin); + this.itemEventListener = new ItemEventListener(plugin, this); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 76f05c35a..db9aff35a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -4,6 +4,7 @@ import io.papermc.paper.event.block.CompostItemEvent; import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent; import net.momirealms.craftengine.bukkit.item.BukkitCustomItem; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; @@ -17,9 +18,11 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.setting.FoodData; +import net.momirealms.craftengine.core.item.updater.ItemUpdateResult; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; @@ -45,13 +48,16 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.enchantment.PrepareItemEnchantEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EnchantingInventory; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; @@ -61,9 +67,11 @@ import java.util.Optional; public class ItemEventListener implements Listener { private final BukkitCraftEngine plugin; + private final BukkitItemManager itemManager; - public ItemEventListener(BukkitCraftEngine plugin) { + public ItemEventListener(BukkitCraftEngine plugin, BukkitItemManager itemManager) { this.plugin = plugin; + this.itemManager = itemManager; } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @@ -534,4 +542,50 @@ public class ItemEventListener implements Listener { serverPlayer.sendPackets(packets, false); }); } + + /* + + 关于物品更新器 + + */ + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onDropItem(PlayerDropItemEvent event) { + if (!Config.triggerUpdateDrop()) return; + org.bukkit.entity.Item itemDrop = event.getItemDrop(); + ItemStack itemStack = itemDrop.getItemStack(); + Item wrapped = this.itemManager.wrap(itemStack); + ItemUpdateResult result = this.itemManager.updateItem(wrapped, () -> ItemBuildContext.of(BukkitAdaptors.adapt(event.getPlayer()))); + if (result.updated()) { + itemDrop.setItemStack((ItemStack) result.finalItem().getItem()); + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onPickUpItem(EntityPickupItemEvent event) { + if (!Config.triggerUpdatePickUp()) return; + if (!(event.getEntity() instanceof Player player)) return; + org.bukkit.entity.Item itemDrop = event.getItem(); + ItemStack itemStack = itemDrop.getItemStack(); + Item wrapped = this.itemManager.wrap(itemStack); + ItemUpdateResult result = this.itemManager.updateItem(wrapped, () -> ItemBuildContext.of(BukkitAdaptors.adapt(player))); + if (result.updated()) { + itemDrop.setItemStack((ItemStack) result.finalItem().getItem()); + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) + public void onInventoryClickItem(InventoryClickEvent event) { + if (!Config.triggerUpdateClick()) return; + if (!(event.getWhoClicked() instanceof Player player)) return; + Inventory clickedInventory = event.getClickedInventory(); + // 点击自己物品栏里的物品 + if (clickedInventory == null || clickedInventory != player.getInventory()) return; + ItemStack currentItem = event.getCurrentItem(); + Item wrapped = this.itemManager.wrap(currentItem); + ItemUpdateResult result = this.itemManager.updateItem(wrapped, () -> ItemBuildContext.of(BukkitAdaptors.adapt(player))); + if (!result.updated() || !result.replaced()) { + return; + } + event.setCurrentItem((ItemStack) result.finalItem().getItem()); + } } diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 2d4cc5ea7..27ead33b2 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -142,6 +142,14 @@ item: client-bound-model: false # Add a tag on custom name and lore non-italic-tag: false + # Determines when to trigger the item updater + # This feature may incur some performance overhead. Please do not enable it unless necessary. + # Correct use case: When you designed incorrect weapon attributes and need to update the values for items already held by players. + # Wrong use case: When you want to update an item's name and lore to a newer version (In this case you should use client-bound-data instead of the item updater) + update-triggers: + click-in-inventory: false # this option won't work for players in creative mode + drop: false + pick-up: false equipment: # The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims) @@ -170,7 +178,7 @@ block: # - Server MUST list ACTUAL CUSTOM BLOCK IDs in item's `can_break` component. # - Sending custom IDs (e.g., craftengine:note_block_0) to vanilla clients WILL CRASH THEM! # ✅ Solution: - # - Use `client-bound-item-data` to safely sync custom block data to clients. + # - Use `client-bound-data` to safely sync custom block data to clients. simplify-adventure-break-check: false # Similar to the option above, but designed for block placement simplify-adventure-place-check: false diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 6244a83e1..213fa69b8 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -243,6 +243,9 @@ warning.config.item.model.special.chest.invalid_openness: "Issue found i warning.config.item.model.special.shulker_box.missing_texture: "Issue found in file - The item '' is missing the required 'texture' argument for special model 'minecraft:shulker_box'." warning.config.item.model.special.shulker_box.invalid_openness: "Issue found in file - The item '' is using an invalid 'openness' value '' for special model 'minecraft:shulker_box'. Valid range '0~1.'" warning.config.item.model.special.head.missing_kind: "Issue found in file - The item '' is missing the required 'kind' argument for special model 'minecraft:head'." +warning.config.item.updater.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for item updater." +warning.config.item.updater.invalid_type: "Issue found in file - The item '' is using an invalid 'type' argument '' for item updater." +warning.config.item.updater.transmute.missing_material: "Issue found in file - The item '' is missing the required 'material' argument for 'transmute' item updater." warning.config.block.duplicate: "Issue found in file - Duplicated block ''. Please check if there is the same configuration in other files." warning.config.block.missing_state: "Issue found in file - The block '' is missing the required 'state' argument." warning.config.block.state.property.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for property ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 93b136d5a..f67146759 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -243,6 +243,9 @@ warning.config.item.model.special.chest.invalid_openness: "在文件 在文件 发现问题 - 物品 '' 的 'minecraft:shulker_box' 特殊模型缺少必需的 'texture' 参数" warning.config.item.model.special.shulker_box.invalid_openness: "在文件 发现问题 - 物品 '' 的 'minecraft:shulker_box' 特殊模型使用了无效的 'openness' 值 '' 有效范围应为 0~1" warning.config.item.model.special.head.missing_kind: "在文件 发现问题 - 物品 '' 的 'minecraft:head' 特殊模型缺少必需的 'kind' 参数" +warning.config.item.updater.missing_type: "在文件 发现问题 - 物品 '' 缺少物品更新器必需的参数 'type'" +warning.config.item.updater.invalid_type: "在文件 发现问题 - 物品 '' 在物品更新器中使用了无效的 'type' 参数值 ''" +warning.config.item.updater.transmute.missing_material: "在文件 发现问题 - 物品 '' 缺少物品转换更新所需的 'material' 参数." warning.config.block.duplicate: "在文件 发现问题 - 重复的方块 '' 请检查其他文件中是否存在相同配置" warning.config.block.missing_state: "在文件 发现问题 - 方块 '' 缺少必需的 'state' 参数" warning.config.block.state.property.missing_type: "在文件 发现问题 - 方块 '' 的属性 '' 缺少必需的 'type' 参数" diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index 336d4c1a7..561d4d9f1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.updater.ItemUpdateConfig; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -24,6 +25,7 @@ public abstract class AbstractCustomItem implements CustomItem { protected final List behaviors; protected final ItemSettings settings; protected final Map>> events; + protected final ItemUpdateConfig updater; @SuppressWarnings("unchecked") public AbstractCustomItem(boolean isVanillaItem, UniqueKey id, Key material, Key clientBoundMaterial, @@ -31,7 +33,8 @@ public abstract class AbstractCustomItem implements CustomItem { List> modifiers, List> clientBoundModifiers, ItemSettings settings, - Map>> events) { + Map>> events, + ItemUpdateConfig updater) { this.isVanillaItem = isVanillaItem; this.id = id; this.material = material; @@ -43,6 +46,7 @@ public abstract class AbstractCustomItem implements CustomItem { this.clientBoundModifiers = clientBoundModifiers.toArray(new ItemDataModifier[0]); this.behaviors = List.copyOf(behaviors); this.settings = settings; + this.updater = updater; } @Override @@ -52,6 +56,11 @@ public abstract class AbstractCustomItem implements CustomItem { } } + @Override + public Optional updater() { + return Optional.ofNullable(this.updater); + } + @Override public Key id() { return this.id.key(); 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 4b18d7194..f2fb1bba1 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 @@ -6,6 +6,10 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.item.equipment.*; import net.momirealms.craftengine.core.item.modifier.*; +import net.momirealms.craftengine.core.item.updater.ItemUpdateConfig; +import net.momirealms.craftengine.core.item.updater.ItemUpdateResult; +import net.momirealms.craftengine.core.item.updater.ItemUpdater; +import net.momirealms.craftengine.core.item.updater.ItemUpdaters; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -30,6 +34,7 @@ import org.incendo.cloud.type.Either; import java.nio.file.Path; import java.util.*; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.stream.Stream; public abstract class AbstractItemManager extends AbstractModelGenerator implements ItemManager { @@ -144,6 +149,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Optional.ofNullable(this.customItemsByPath.get(path)); } + @Override + public ItemUpdateResult updateItem(Item item, Supplier contextSupplier) { + Optional> optionalCustomItem = item.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + Optional updater = customItem.updater(); + if (updater.isPresent()) { + return updater.get().update(item, contextSupplier); + } + } + return new ItemUpdateResult(item, false, false); + } + @Override public boolean addCustomItem(CustomItem customItem) { Key id = customItem.id(); @@ -417,6 +435,25 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl behaviors = Collections.emptyList(); } + // 如果有物品更新器 + if (section.containsKey("updater")) { + Map updater = ResourceConfigUtils.getAsMap(section.get("updater"), "updater"); + List versions = new ArrayList<>(2); + for (Map.Entry entry : updater.entrySet()) { + try { + int version = Integer.parseInt(entry.getKey()); + versions.add(new ItemUpdateConfig.Version( + version, + ResourceConfigUtils.parseConfigAsList(entry.getValue(), map -> ItemUpdaters.fromMap(id, map)).toArray(new ItemUpdater[0]) + )); + } catch (NumberFormatException ignored) { + } + } + ItemUpdateConfig config = new ItemUpdateConfig(versions); + itemBuilder.updater(config); + itemBuilder.dataModifier(new ItemVersionModifier<>(config.maxVersion())); + } + // 构建自定义物品 CustomItem customItem = itemBuilder .isVanillaItem(isVanillaItem) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 5d0415a30..b02cbea0b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.updater.ItemUpdateConfig; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -11,6 +12,7 @@ import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Map; +import java.util.Optional; public interface CustomItem extends BuildableItem { @@ -32,6 +34,8 @@ public interface CustomItem extends BuildableItem { ItemSettings settings(); + Optional updater(); + default boolean is(Key tag) { return settings().tags().contains(tag); } @@ -64,6 +68,8 @@ public interface CustomItem extends BuildableItem { Builder settings(ItemSettings settings); + Builder updater(ItemUpdateConfig updater); + Builder events(Map>> events); CustomItem build(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 9be0dfb7f..4f34eff44 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.equipment.Equipment; import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult; import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; +import net.momirealms.craftengine.core.item.updater.ItemUpdateResult; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.ModernItemModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; @@ -18,6 +19,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Supplier; public interface ItemManager extends Manageable, ModelGenerator { @@ -114,4 +116,6 @@ public interface ItemManager extends Manageable, ModelGenerator { Item applyTrim(Item base, Item addition, Item template, Key pattern); Item build(DatapackRecipeResult result); + + ItemUpdateResult updateItem(Item item, Supplier contextSupplier); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java index 33f4bb98f..b2b636f60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentsModifier.java @@ -37,7 +37,7 @@ public class ArgumentsModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { if (VersionHelper.isOrAbove1_20_5()) { - CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElse(new CompoundTag()); + CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElseGet(CompoundTag::new); CompoundTag argumentTag = new CompoundTag(); for (Map.Entry entry : this.arguments.entrySet()) { argumentTag.put(entry.getKey(), new StringTag(entry.getValue().get(context))); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index d2eb6a9c4..402efa393 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -31,6 +31,7 @@ public final class ItemDataModifiers { public static final Key ATTRIBUTE_MODIFIERS = Key.of("craftengine:attribute-modifiers"); public static final Key ATTRIBUTES = Key.of("craftengine:attributes"); public static final Key ARGUMENTS = Key.of("craftengine:arguments"); + public static final Key VERSION = Key.of("craftengine:version"); public static final Key ITEM_NAME = Key.of("craftengine:item-name"); public static final Key OVERWRITABLE_ITEM_NAME = Key.of("craftengine:overwritable-item-name"); public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemVersionModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemVersionModifier.java new file mode 100644 index 000000000..b3002918e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemVersionModifier.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; + +import java.util.Optional; + +public class ItemVersionModifier implements ItemDataModifier { + public static final String VERSION_TAG = "craftengine:version"; + private final int version; + + public ItemVersionModifier(int version) { + this.version = version; + } + + public int version() { + return this.version; + } + + @Override + public Key type() { + return ItemDataModifiers.VERSION; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (VersionHelper.isOrAbove1_20_5()) { + CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElseGet(CompoundTag::new); + customData.putInt(VERSION_TAG, this.version); + item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData); + } else { + item.setTag(this.version, VERSION_TAG); + } + return item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateConfig.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateConfig.java new file mode 100644 index 000000000..9ed2df898 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateConfig.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.core.item.updater; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.modifier.ItemVersionModifier; +import net.momirealms.sparrow.nbt.NumericTag; +import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class ItemUpdateConfig { + private final List versions; + private final int maxVersion; + + public ItemUpdateConfig(List versions) { + this.versions = new ArrayList<>(versions); + this.versions.sort(Version::compareTo); + int maxVersion = 0; + for (Version version : versions) { + maxVersion = Math.max(maxVersion, version.version); + } + this.maxVersion = maxVersion; + } + + public int maxVersion() { + return maxVersion; + } + + public ItemUpdateResult update(Item item, Supplier context) { + Tag versionTag = item.getTag(ItemVersionModifier.VERSION_TAG); + int currentVersion = 0; + if (versionTag instanceof NumericTag numericTag) { + currentVersion = numericTag.getAsInt(); + } + if (currentVersion >= this.maxVersion) { + return new ItemUpdateResult(item, false, false); + } + ItemBuildContext buildContext = context.get(); + Item orginalItem = item; + for (Version version : this.versions) { + if (currentVersion < version.version) { + item = version.apply(item, buildContext); + } + } + item.setTag(this.maxVersion, ItemVersionModifier.VERSION_TAG); + return new ItemUpdateResult(item, orginalItem != item, true); + } + + public record Version(int version, ItemUpdater[] updaters) implements Comparable { + + @SuppressWarnings("unchecked") + public Item apply(Item item, ItemBuildContext context) { + for (ItemUpdater updater : (ItemUpdater[]) updaters) { + item = updater.update(item, context); + } + return item; + } + + @Override + public int compareTo(@NotNull ItemUpdateConfig.Version o) { + return Integer.compare(this.version, o.version); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateResult.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateResult.java new file mode 100644 index 000000000..89b313971 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdateResult.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.item.updater; + +import net.momirealms.craftengine.core.item.Item; + +public record ItemUpdateResult(Item finalItem, boolean replaced, boolean updated) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdater.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdater.java new file mode 100644 index 000000000..842b25e23 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdater.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.item.updater; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; + +public interface ItemUpdater { + + Item update(Item item, ItemBuildContext context); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaterType.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaterType.java new file mode 100644 index 000000000..2b81e9a29 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaterType.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.item.updater; + +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public interface ItemUpdaterType { + + ItemUpdater create(Key item, Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaters.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaters.java new file mode 100644 index 000000000..9740c9fd9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/ItemUpdaters.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.item.updater; + +import net.momirealms.craftengine.core.item.updater.impl.ApplyDataOperation; +import net.momirealms.craftengine.core.item.updater.impl.ResetOperation; +import net.momirealms.craftengine.core.item.updater.impl.TransmuteOperation; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.Map; + +@SuppressWarnings("unchecked") +public class ItemUpdaters { + public static final Key APPLY_DATA = Key.of("craftengine:apply_data"); + public static final Key TRANSMUTE = Key.of("craftengine:transmute"); + public static final Key RESET = Key.of("craftengine:reset"); + + static { + register(APPLY_DATA, ApplyDataOperation.TYPE); + register(TRANSMUTE, TransmuteOperation.TYPE); + register(RESET, ResetOperation.TYPE); + } + + public static void register(Key id, ItemUpdaterType type) { + WritableRegistry> registry = (WritableRegistry>) BuiltInRegistries.ITEM_UPDATER_TYPE; + registry.register(ResourceKey.create(Registries.ITEM_UPDATER_TYPE.location(), id), type); + } + + public static ItemUpdater fromMap(Key item, Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.updater.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + ItemUpdaterType updaterType = (ItemUpdaterType) BuiltInRegistries.ITEM_UPDATER_TYPE.getValue(key); + if (updaterType == null) { + throw new LocalizedResourceConfigException("warning.config.item.updater.invalid_type", type); + } + return updaterType.create(item, map); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ApplyDataOperation.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ApplyDataOperation.java new file mode 100644 index 000000000..53d06471d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ApplyDataOperation.java @@ -0,0 +1,49 @@ +package net.momirealms.craftengine.core.item.updater.impl; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.updater.ItemUpdater; +import net.momirealms.craftengine.core.item.updater.ItemUpdaterType; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ApplyDataOperation implements ItemUpdater { + public static final Type TYPE = new Type<>(); + private final List> modifiers; + + public ApplyDataOperation(List> modifiers) { + this.modifiers = modifiers; + } + + @Override + public Item update(Item item, ItemBuildContext context) { + if (this.modifiers != null) { + for (ItemDataModifier modifier : this.modifiers) { + modifier.apply(item, context); + } + } + return item; + } + + public static class Type implements ItemUpdaterType { + + @SuppressWarnings("unchecked") + @Override + public ItemUpdater create(Key item, Map args) { + List> modifiers = new ArrayList<>(); + Map data = ResourceConfigUtils.getAsMap(args.get("data"), "data"); + for (Map.Entry entry : data.entrySet()) { + Optional.ofNullable(BuiltInRegistries.ITEM_DATA_MODIFIER_FACTORY.getValue(Key.withDefaultNamespace(entry.getKey(), Key.DEFAULT_NAMESPACE))) + .ifPresent(factory -> modifiers.add((ItemDataModifier) factory.create(entry.getValue()))); + } + return new ApplyDataOperation<>(modifiers); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ResetOperation.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ResetOperation.java new file mode 100644 index 000000000..f0d7d2d5d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/ResetOperation.java @@ -0,0 +1,63 @@ +package net.momirealms.craftengine.core.item.updater.impl; + +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemManager; +import net.momirealms.craftengine.core.item.updater.ItemUpdater; +import net.momirealms.craftengine.core.item.updater.ItemUpdaterType; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.LazyReference; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.List; +import java.util.Map; + +public class ResetOperation implements ItemUpdater { + public static final Type TYPE = new Type<>(); + private final LazyReference> item; + private final List componentsToKeep; + private final List tagsToKeep; + + public ResetOperation(LazyReference> item, List componentsToKeep, List tagsToKeep) { + this.componentsToKeep = componentsToKeep; + this.tagsToKeep = tagsToKeep; + this.item = item; + } + + @Override + public Item update(Item item, ItemBuildContext context) { + Item newItem = this.item.get().buildItem(context); + if (VersionHelper.COMPONENT_RELEASE) { + for (Key component : this.componentsToKeep) { + if (item.hasComponent(component)) { + newItem.setExactComponent(component, item.getExactComponent(component)); + } + } + } else { + for (String[] nbt : this.tagsToKeep) { + if (item.hasTag((Object[]) nbt)) { + newItem.setTag(item.getTag((Object[]) nbt), (Object[]) nbt); + } + } + } + return newItem; + } + + public static class Type implements ItemUpdaterType { + + @Override + public ItemUpdater create(Key item, Map args) { + return new ResetOperation<>( + LazyReference.lazyReference(() -> { + ItemManager itemManager = CraftEngine.instance().itemManager(); + return itemManager.getCustomItem(item).orElseThrow(); + }), + MiscUtils.getAsStringList(args.get("keep-components")).stream().map(Key::of).toList(), + MiscUtils.getAsStringList(args.get("keep-tags")).stream().map(tag -> tag.split("\\.")).toList() + ); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/TransmuteOperation.java b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/TransmuteOperation.java new file mode 100644 index 000000000..fe046191f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/updater/impl/TransmuteOperation.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.core.item.updater.impl; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.updater.ItemUpdater; +import net.momirealms.craftengine.core.item.updater.ItemUpdaterType; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class TransmuteOperation implements ItemUpdater { + public static final Type TYPE = new Type<>(); + private final Key newMaterial; + + public TransmuteOperation(Key newMaterial) { + this.newMaterial = newMaterial; + } + + @Override + public Item update(Item item, ItemBuildContext context) { + return item.transmuteCopy(this.newMaterial, item.count()); + } + + public static class Type implements ItemUpdaterType { + + @Override + public ItemUpdater create(Key item, Map args) { + return new TransmuteOperation<>(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("material"), "warning.config.item.updater.transmute.missing_material"))); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 8439a43d6..6c1fe4b11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -151,6 +151,10 @@ public class Config { protected boolean item$client_bound_model; protected boolean item$non_italic_tag; + protected boolean item$update_triggers$attack; + protected boolean item$update_triggers$click_in_inventory; + protected boolean item$update_triggers$drop; + protected boolean item$update_triggers$pick_up; protected String equipment$sacrificed_vanilla_armor$type; protected Key equipment$sacrificed_vanilla_armor$asset_id; @@ -359,6 +363,10 @@ public class Config { // item item$client_bound_model = config.getBoolean("item.client-bound-model", false); item$non_italic_tag = config.getBoolean("item.non-italic-tag", false); + item$update_triggers$attack = config.getBoolean("item.update-triggers.attack", false); + item$update_triggers$click_in_inventory = config.getBoolean("item.update-triggers.click-in-inventory", false); + item$update_triggers$drop = config.getBoolean("item.update-triggers.drop", false); + item$update_triggers$pick_up = config.getBoolean("item.update-triggers.pick-up", false); // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -835,6 +843,22 @@ public class Config { return instance.recipe$ingredient_sources; } + public static boolean triggerUpdateAttack() { + return instance.item$update_triggers$attack; + } + + public static boolean triggerUpdateClick() { + return instance.item$update_triggers$click_in_inventory; + } + + public static boolean triggerUpdatePickUp() { + return instance.item$update_triggers$pick_up; + } + + public static boolean triggerUpdateDrop() { + return instance.item$update_triggers$drop; + } + public void setObf(boolean enable) { this.resource_pack$protection$obfuscation$enable = enable; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 482b2e1d5..806b20c22 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; +import net.momirealms.craftengine.core.item.updater.ItemUpdaterType; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -79,6 +80,7 @@ public class BuiltInRegistries { public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); public static final Registry> RECIPE_POST_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.RECIPE_POST_PROCESSOR_TYPE); + public static final Registry> ITEM_UPDATER_TYPE = createConstantBoundRegistry(Registries.ITEM_UPDATER_TYPE); private static Registry createConstantBoundRegistry(ResourceKey> key) { return new ConstantBoundRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index 78e68ec0e..d06a53394 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; +import net.momirealms.craftengine.core.item.updater.ItemUpdaterType; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -81,4 +82,5 @@ public class Registries { public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); public static final ResourceKey>> RECIPE_POST_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_post_processor_type")); + public static final ResourceKey>> ITEM_UPDATER_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_updater_type")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/SingularPalette.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/SingularPalette.java index 4930529c9..35736ff09 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/SingularPalette.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/SingularPalette.java @@ -18,7 +18,7 @@ public class SingularPalette implements Palette { this.idList = idList; this.listener = listener; if (!entries.isEmpty()) { - this.entry = entries.get(0); + this.entry = entries.getFirst(); } } diff --git a/gradle.properties b/gradle.properties index b3c3e3382..4ce25d07a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.61.7 -config_version=43 -lang_version=23 +project_version=0.0.61.8 +config_version=44 +lang_version=24 project_group=net.momirealms latest_supported_version=1.21.8 From 3fc0988c1301d36a7b72e85ba14b9d3d06952191 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 18 Aug 2025 16:13:19 +0800 Subject: [PATCH 46/57] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=B7=B2=E6=9C=89?= =?UTF-8?q?=E6=96=9C=E4=BD=93=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/item/modifier/lore/LoreModifier.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 2068fbcc9..63e494b3a 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 @@ -66,7 +66,7 @@ public sealed interface LoreModifier extends SimpleNetworkItemDataModifier } } return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, - Arrays.stream(rawLore).map(line -> Config.addNonItalicTag() ? FormattedLine.create("" + line) : FormattedLine.create(line)) + Arrays.stream(rawLore).map(line -> Config.addNonItalicTag() && !line.startsWith("") ? FormattedLine.create("" + line) : FormattedLine.create(line)) .toArray(FormattedLine[]::new))); } @@ -79,7 +79,7 @@ public sealed interface LoreModifier extends SimpleNetworkItemDataModifier 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, - Arrays.stream(content).map(line -> Config.addNonItalicTag() ? FormattedLine.create("" + line) : FormattedLine.create(line)) + Arrays.stream(content).map(line -> Config.addNonItalicTag() && !line.startsWith("") ? FormattedLine.create("" + line) : FormattedLine.create(line)) .toArray(FormattedLine[]::new)), lastPriority)); } } From b0e26190820e1908887f15da4067ddc019b8086a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 19 Aug 2025 05:15:11 +0800 Subject: [PATCH 47/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 31 ++++++----- .../core/item/modifier/ItemDataModifiers.java | 2 + .../core/item/modifier/PDCModifier.java | 54 +++++++++++++++++++ 3 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 4c404b53f..bb3ef7aaf 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 @@ -7,13 +7,16 @@ import net.momirealms.craftengine.core.block.parser.BlockStateParser; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Location; +import org.bukkit.block.data.BlockData; import org.bukkit.command.CommandSender; import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; import org.incendo.cloud.bukkit.parser.location.LocationParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.IntegerParser; import org.incendo.cloud.parser.standard.StringParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; @@ -30,20 +33,22 @@ public class TestCommand extends BukkitCommandFeature { @Override public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .required("location", LocationParser.locationParser()) - .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { - @Override - public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(BlockStateParser.fillSuggestions(input.input(), input.cursor()).stream().map(Suggestion::suggestion).collect(Collectors.toList())); - } - })) + .required("start", IntegerParser.integerParser(0)) + .senderType(Player.class) .handler(context -> { - String data = context.get("id"); - Location location = context.get("location"); - ImmutableBlockState state = BlockStateParser.deserialize(data); - if (state == null) return; - Minecart minecart = location.getWorld().spawn(location, Minecart.class); - minecart.setDisplayBlockData(BlockStateUtils.fromBlockData(state.customBlockState().handle())); + Player sender = context.sender(); + int start = context.get("start"); + int x = sender.getChunk().getX() * 16; + int z = sender.getChunk().getZ() * 16; + int y = (sender.getLocation().getBlockY() / 16) * 16; + for (int a = 0; a < 16; a++) { + for (int b = 0; b < 16; b++) { + for (int c = 0; c < 16; c++) { + BlockData blockData = BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(start + a + b * 16 + c * 256)); + sender.getWorld().setBlockData(new Location(sender.getWorld(), x + a, y + b, z + c), blockData); + } + } + } }); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index 402efa393..2b6672de8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -32,6 +32,7 @@ public final class ItemDataModifiers { public static final Key ATTRIBUTES = Key.of("craftengine:attributes"); public static final Key ARGUMENTS = Key.of("craftengine:arguments"); public static final Key VERSION = Key.of("craftengine:version"); + public static final Key PDC = Key.of("craftengine:pdc"); public static final Key ITEM_NAME = Key.of("craftengine:item-name"); public static final Key OVERWRITABLE_ITEM_NAME = Key.of("craftengine:overwritable-item-name"); public static final Key JUKEBOX_PLAYABLE = Key.of("craftengine:jukebox-playable"); @@ -74,6 +75,7 @@ public final class ItemDataModifiers { register(HIDE_TOOLTIP, HideTooltipModifier.FACTORY); register(ARGUMENTS, ArgumentsModifier.FACTORY); register(OVERWRITABLE_ITEM_NAME, OverwritableItemNameModifier.FACTORY); + register(PDC, PDCModifier.FACTORY); if (VersionHelper.isOrAbove1_20_5()) { register(CUSTOM_NAME, CustomNameModifier.FACTORY); register(ITEM_NAME, ItemNameModifier.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java new file mode 100644 index 000000000..b6a52e91d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java @@ -0,0 +1,54 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class PDCModifier implements ItemDataModifier { + public static final String BUKKIT_PDC = "PublicBukkitValues"; + public static final Factory FACTORY = new Factory<>(); + private final CompoundTag data; + + public PDCModifier(CompoundTag data) { + this.data = data; + } + + @Override + public Key type() { + return ItemDataModifiers.PDC; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (VersionHelper.isOrAbove1_20_5()) { + CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElseGet(CompoundTag::new); + customData.put(BUKKIT_PDC, this.data); + item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData); + } else { + item.setTag(this.data, BUKKIT_PDC); + } + return item; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + Map data = ResourceConfigUtils.getAsMap(arg, "pdc"); + CompoundTag tag = (CompoundTag) CraftEngine.instance().platform().javaToSparrowNBT(data); + return new PDCModifier<>(tag); + } + } +} From 2405fbecda40b398309089566e6d830a3d2effac Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 19 Aug 2025 06:17:00 +0800 Subject: [PATCH 48/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E8=B0=83=E8=89=B2=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 5 +- .../plugin/network/PacketConsumers.java | 66 +++++++++---------- .../core/world/chunk/IdListPalette.java | 4 ++ .../core/world/chunk/PalettedContainer.java | 46 +++++++------ .../core/world/chunk/packet/MCSection.java | 18 ++--- gradle.properties | 2 +- 6 files changed, 75 insertions(+), 66 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 47d6cf89e..97d99df9c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -43,6 +43,7 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.Sounds; import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -327,7 +328,9 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.realBlockArranger = builder3.build(); this.registeredBlocks = builder4.build(); this.blockRegisterOrder = ImmutableList.copyOf(order); - + if (MCUtils.ceilLog2(BlockStateUtils.vanillaStateSize() + counter) == MCUtils.ceilLog2(BlockStateUtils.vanillaStateSize())) { + PalettedContainer.NEED_DOWNGRADE = false; + } for (Object block : (Iterable) MBuiltInRegistries.BLOCK) { Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block); if (affectedBlockSounds.contains(soundType)) { 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 8d9028a65..2fc91c8af 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 @@ -89,7 +89,8 @@ public class PacketConsumers { private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; private static int[] BLOCK_STATE_MAPPINGS; private static int[] MOD_BLOCK_STATE_MAPPINGS; - private static IntIdentityList BLOCK_LIST; + private static IntIdentityList SERVER_BLOCK_LIST; + private static IntIdentityList CLIENT_BLOCK_LIST; private static IntIdentityList BIOME_LIST; public static void initEntities(int registrySize) { @@ -245,7 +246,8 @@ public class PacketConsumers { } BLOCK_STATE_MAPPINGS = newMappings; MOD_BLOCK_STATE_MAPPINGS = newMappingsMOD; - BLOCK_LIST = new IntIdentityList(registrySize); + SERVER_BLOCK_LIST = new IntIdentityList(registrySize); + CLIENT_BLOCK_LIST = new IntIdentityList(BlockStateUtils.vanillaStateSize()); BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); } @@ -306,26 +308,22 @@ public class PacketConsumers { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - try { - MCSection mcSection = new MCSection(BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remapMOD); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remapMOD(state); - if (newState != state) { - container.set(j, newState); - } + MCSection mcSection = new MCSection(SERVER_BLOCK_LIST, SERVER_BLOCK_LIST, BIOME_LIST); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(PacketConsumers::remapMOD); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = remapMOD(state); + if (newState != state) { + container.set(j, newState); } } - mcSection.writePacket(newBuf); - } catch (Exception e) { - break; } + mcSection.writePacket(newBuf); } buffer = newBuf.array(); } else { @@ -333,26 +331,22 @@ public class PacketConsumers { FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - try { - MCSection mcSection = new MCSection(BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remap); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remap(state); - if (newState != state) { - container.set(j, newState); - } + MCSection mcSection = new MCSection(CLIENT_BLOCK_LIST, SERVER_BLOCK_LIST, BIOME_LIST); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(PacketConsumers::remap); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = remap(state); + if (newState != state) { + container.set(j, newState); } } - mcSection.writePacket(newBuf); - } catch (Exception e) { - break; } + mcSection.writePacket(newBuf); } buffer = newBuf.array(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/IdListPalette.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/IdListPalette.java index 362948919..2775ccc51 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/IdListPalette.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/IdListPalette.java @@ -39,6 +39,10 @@ public class IdListPalette implements Palette { } } + public IndexedIterable idList() { + return idList; + } + @Override public int getSize() { return this.idList.size(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java index de064dbe6..e5f704471 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java @@ -16,13 +16,11 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.IntUnaryOperator; -import java.util.function.Predicate; +import java.util.function.*; import java.util.stream.LongStream; public class PalettedContainer implements PaletteResizeListener, ReadableContainer { + public static boolean NEED_DOWNGRADE = true; private static final BiConsumer RAW_DATA_WRITER = VersionHelper.isOrAbove1_21_5() ? (FriendlyByteBuf::writeFixedSizeLongArray) : (FriendlyByteBuf::writeLongArray); private static final BiConsumer RAW_DATA_READER = VersionHelper.isOrAbove1_21_5() ? @@ -74,31 +72,34 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC return false; } + public PalettedContainer downgradeTo(IndexedIterable idList) { + if (!NEED_DOWNGRADE) { + return this; + } + Palette palette = this.data.palette; + if (!(palette instanceof IdListPalette idListPalette)) { + return this; + } + Data newData = getCompatibleData(this.data, idList, 128); + newData.importFrom(idListPalette, this.data.storage); + return new PalettedContainer<>(idList, PaletteProvider.BLOCK_STATE, newData); + } + public Data data() { return data; } public void readPacket(FriendlyByteBuf buf) { - this.lock(); - try { - int i = buf.readByte(); - Data data = this.getCompatibleData(this.data, i); - data.palette.readPacket(buf); - RAW_DATA_READER.accept(buf, data.storage.getData()); - this.data = data; - } finally { - this.unlock(); - } + int i = buf.readByte(); + Data data = this.getCompatibleData(this.data, i); + data.palette.readPacket(buf); + RAW_DATA_READER.accept(buf, data.storage.getData()); + this.data = data; } @Override public void writePacket(FriendlyByteBuf buf) { - this.lock(); - try { - this.data.writePacket(buf); - } finally { - this.unlock(); - } + this.data.writePacket(buf); } private Data getCompatibleData(@Nullable Data previousData, int bits) { @@ -106,6 +107,11 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC return previousData != null && dataProvider.equals(previousData.configuration()) ? previousData : dataProvider.createData(this.idList, this, this.paletteProvider.getContainerSize()); } + private Data getCompatibleData(@Nullable Data previousData, IndexedIterable idList, int bits) { + DataProvider dataProvider = this.paletteProvider.createDataProvider(idList, bits); + return previousData != null && dataProvider.equals(previousData.configuration()) ? previousData : dataProvider.createData(this.idList, this, this.paletteProvider.getContainerSize()); + } + @Override public int onResize(int i, T object) { Data oldData = this.data; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java index 8c9f37387..d0931a2ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java @@ -7,17 +7,19 @@ import net.momirealms.craftengine.core.world.chunk.ReadableContainer; public class MCSection { private short nonEmptyBlockCount; - private final PalettedContainer blockStateContainer; + private final PalettedContainer serverBlockStateContainer; + private final IndexedIterable clientBlockStateList; private ReadableContainer biomeContainer; - public MCSection(IndexedIterable blockStateList, IndexedIterable biomeList) { - this.blockStateContainer = new PalettedContainer<>(blockStateList, 0, PalettedContainer.PaletteProvider.BLOCK_STATE); + public MCSection(IndexedIterable clientBlockStateList, IndexedIterable serverBlockStateList, IndexedIterable biomeList) { + this.serverBlockStateContainer = new PalettedContainer<>(serverBlockStateList, 0, PalettedContainer.PaletteProvider.BLOCK_STATE); this.biomeContainer = new PalettedContainer<>(biomeList, 0, PalettedContainer.PaletteProvider.BIOME); + this.clientBlockStateList = clientBlockStateList; } public void readPacket(FriendlyByteBuf buf) { this.nonEmptyBlockCount = buf.readShort(); - this.blockStateContainer.readPacket(buf); + this.serverBlockStateContainer.readPacket(buf); PalettedContainer palettedContainer = this.biomeContainer.slice(); palettedContainer.readPacket(buf); this.biomeContainer = palettedContainer; @@ -25,19 +27,19 @@ public class MCSection { public void writePacket(FriendlyByteBuf buf) { buf.writeShort(this.nonEmptyBlockCount); - this.blockStateContainer.writePacket(buf); + this.serverBlockStateContainer.downgradeTo(this.clientBlockStateList).writePacket(buf); this.biomeContainer.writePacket(buf); } public void setBlockState(int x, int y, int z, int state) { - this.blockStateContainer.set(x, y, z, state); + this.serverBlockStateContainer.set(x, y, z, state); } public int getBlockState(int x, int y, int z) { - return this.blockStateContainer.get(x, y, z); + return this.serverBlockStateContainer.get(x, y, z); } public PalettedContainer blockStateContainer() { - return blockStateContainer; + return serverBlockStateContainer; } } diff --git a/gradle.properties b/gradle.properties index 4ce25d07a..b0232b2c6 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.61.8 +project_version=0.0.61.9 config_version=44 lang_version=24 project_group=net.momirealms From 80279d3b89115dd166ff0533b7b8fb3b260811ab Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 19 Aug 2025 22:22:07 +0800 Subject: [PATCH 49/57] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b0232b2c6..db85c383c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 -anti_grief_version=0.18 +anti_grief_version=0.19 nms_helper_version=1.0.57 evalex_version=3.5.0 reactive_streams_version=1.0.4 From c54ce3b6606bb9490f8a1712ada377461dfa72a8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 17:35:35 +0800 Subject: [PATCH 50/57] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 24 ++++++++++++------- gradle.properties | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 0fcba6c05..519734e35 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -403,7 +403,18 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.plugin.logger().warn("Failed to load datapack recipes", e); } } + + if (Config.disableAllVanillaRecipes()) { + this.recipesToUnregister.addAll(this.lastDatapackRecipes.keySet().stream().map(it -> Pair.of(it, false)).toList()); + return; + } + + boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); for (Map.Entry> entry : this.lastDatapackRecipes.entrySet()) { + if (hasDisabledAny && Config.disabledVanillaRecipes().contains(entry.getKey())) { + this.recipesToUnregister.add(Pair.of(entry.getKey(), false)); + continue; + } markAsDataPackRecipe(entry.getKey()); registerInternalRecipe(entry.getKey(), entry.getValue()); } @@ -420,19 +431,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager { packResources.add(CoreReflections.methodHandle$Pack$open.invokeExact(pack)); } Map> recipes = new HashMap<>(); - boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); + try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.methodHandle$MultiPackResourceManagerConstructor.invokeExact(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { Map scannedResources = (Map) CoreReflections.methodHandle$FileToIdConverter$listMatchingResources.invokeExact(fileToIdConverter, resourceManager); for (Map.Entry entry : scannedResources.entrySet()) { Key id = extractKeyFromResourceLocation(entry.getKey().toString()); - if (Config.disableAllVanillaRecipes()) { - this.recipesToUnregister.add(new Pair<>(id, false)); - continue; - } - if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) { - this.recipesToUnregister.add(new Pair<>(id, false)); - continue; - } Reader reader = (Reader) CoreReflections.methodHandle$Resource$openAsReader.invokeExact(entry.getValue()); JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); Key serializerType = Key.of(jsonObject.get("type").getAsString()); @@ -470,6 +473,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager { for (Pair pair : this.recipesToUnregister) { unregisterPlatformRecipeMainThread(pair.left(), pair.right()); } + + this.recipesToUnregister.clear(); + // 注册新的配方 for (Recipe recipe : this.byId.values()) { try { diff --git a/gradle.properties b/gradle.properties index db85c383c..564230f8d 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.61.9 +project_version=0.0.61.10 config_version=44 lang_version=24 project_group=net.momirealms From 9b3c2e767d2d997e2382e5b76faff7d4dbcbe6e6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 21:38:18 +0800 Subject: [PATCH 51/57] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=EF=BC=8C=E5=85=81=E8=AE=B8=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=A4=9A=E7=BB=91=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 275 ++---------------- .../plugin/command/feature/TestCommand.java | 13 - .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + .../core/block/AbstractBlockManager.java | 75 ++++- .../core/block/AbstractCustomBlock.java | 15 +- .../craftengine/core/block/BlockManager.java | 2 - .../core/item/modifier/PDCModifier.java | 3 - .../core/util/ResourceConfigUtils.java | 11 + .../core/world/chunk/PalettedContainer.java | 5 +- 10 files changed, 119 insertions(+), 282 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 97d99df9c..d3c7709fd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -3,8 +3,6 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; @@ -26,16 +24,7 @@ import net.momirealms.craftengine.bukkit.util.TagUtils; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; import net.momirealms.craftengine.core.block.parser.BlockStateParser; -import net.momirealms.craftengine.core.block.properties.Properties; -import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.pack.ResourceLocation; -import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; -import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -47,7 +36,6 @@ import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -69,14 +57,12 @@ import java.util.function.Predicate; public final class BukkitBlockManager extends AbstractBlockManager { private static BukkitBlockManager instance; private final BukkitCraftEngine plugin; - private final BlockParser blockParser; + // The total amount of blocks registered private int customBlockCount; private ImmutableBlockState[] stateId2ImmutableBlockStates; // Minecraft objects // Cached new blocks $ holders - private Map internalId2StateId; - private Map registeredBlocks; private Map stateId2BlockHolder; // This map is used to change the block states that are not necessarily needed into a certain block state private Map blockAppearanceMapper; @@ -100,7 +86,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { super(plugin); instance = this; this.plugin = plugin; - this.blockParser = new BlockParser(); this.initVanillaRegistry(); this.loadMappingsAndAdditionalBlocks(); this.registerBlocks(); @@ -230,12 +215,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { } @Override - public ConfigParser parser() { - return this.blockParser; - } - - @Override - public void addBlock(Key id, CustomBlock customBlock) { + public void addBlockInternal(Key id, CustomBlock customBlock) { // bind appearance and real state for (ImmutableBlockState state : customBlock.variantProvider().states()) { ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; @@ -246,7 +226,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId()); this.appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new IntArrayList()).add(state.customBlockState().registryId()); } - super.addBlock(id, customBlock); + super.addBlockInternal(id, customBlock); } @Override @@ -254,6 +234,11 @@ public final class BukkitBlockManager extends AbstractBlockManager { return BlockStateUtils.getBlockOwnerIdFromState(state.handle()); } + @Override + protected Key getBlockOwnerId(int id) { + return BlockStateUtils.getBlockOwnerIdFromState(BlockStateUtils.idToBlockState(id)); + } + @Override public int availableAppearances(Key blockType) { return Optional.ofNullable(this.registeredRealBlockSlots.get(blockType)).orElse(0); @@ -300,6 +285,11 @@ public final class BukkitBlockManager extends AbstractBlockManager { BlockStateUtils.init(vanillaStateCount); } + @Override + protected CustomBlock.Builder platformBuilder(Key id) { + return BukkitCustomBlock.builder(id); + } + @SuppressWarnings("unchecked") private void registerBlocks() { this.plugin.logger().info("Registering blocks. Please wait..."); @@ -406,225 +396,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { return cachedUpdateTagsPacket; } - public class BlockParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; - - @Override - public String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - @Override - public int loadingSequence() { - return LoadingSequence.BLOCK; - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (id.namespace().equals("minecraft") && Registry.MATERIAL.get(KeyUtils.toNamespacedKey(id)) != null) { - parseVanillaBlock(pack, path, id, section); - } else { - // check duplicated config - if (BukkitBlockManager.this.byId.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.block.duplicate"); - } - parseCustomBlock(pack, path, id, section); - } - } - - private void parseCustomBlock(Pack pack, Path path, Key id, Map section) { - // read block settings - BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); - // read states - Map> properties; - Map appearances; - Map variants; - - Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); - boolean singleState = !stateSection.containsKey("properties"); - // single state - if (singleState) { - properties = Map.of(); - int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); - VanillaBlockState vanillaBlock = getVanillaBlock(id, stateSection); - appearances = Map.of("", vanillaBlock.registryId()); - Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, vanillaBlock.type().value() + "_" + internalId); - int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); - if (internalBlockRegistryId == -1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(vanillaBlock.type()) - 1)); - } - variants = Map.of("", new BlockStateVariant("", settings, internalBlockRegistryId)); - } else { - // properties - properties = getProperties(MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), true)); - // appearance - appearances = new HashMap<>(); - Map appearance2BlockType = new HashMap<>(); - for (Map.Entry appearanceEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), false).entrySet()) { - if (appearanceEntry.getValue() instanceof Map) { - VanillaBlockState vanillaBlock = getVanillaBlock(id, MiscUtils.castToMap(appearanceEntry.getValue(), false)); - appearances.put(appearanceEntry.getKey(), vanillaBlock.registryId()); - appearance2BlockType.put(appearanceEntry.getKey(), vanillaBlock.type()); - } - } - // variants - variants = new HashMap<>(); - for (Map.Entry variantEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), false).entrySet()) { - if (variantEntry.getValue() instanceof Map) { - Map variantSection = MiscUtils.castToMap(variantEntry.getValue(), false); - String variantNBT = variantEntry.getKey(); - String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); - if (!appearances.containsKey(appearance)) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); - } - int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); - Key baseBlock = appearance2BlockType.get(appearance); - Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId); - int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); - if (internalBlockRegistryId == -1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1)); - } - Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); - variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); - } - } - } - - CustomBlock block = BukkitCustomBlock.builder(id) - .appearances(appearances) - .variantMapper(variants) - .properties(properties) - .settings(settings) - .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) - .behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))) - .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) - .build(); - - addBlock(id, block); - } - - private void parseVanillaBlock(Pack pack, Path path, Key id, Map section) { - Map settings = MiscUtils.castToMap(section.get("settings"), true); - if (settings != null) { - Object clientBoundTags = settings.get("client-bound-tags"); - if (clientBoundTags instanceof List list) { - List clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList(); - Object nmsBlock = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)); - FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, nmsBlock).ifPresent(i -> - BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags)); - } - } - } - } - - @NotNull - private Map> getProperties(Map propertiesSection) { - Map> properties = new HashMap<>(); - for (Map.Entry entry : propertiesSection.entrySet()) { - Property property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(entry.getValue(), false)); - properties.put(entry.getKey(), property); - } - return properties; - } - - @NotNull - private VanillaBlockState getVanillaBlock(Key id, Map section) { - // require state non null - String vanillaBlockStateTag = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("state"), "warning.config.block.state.missing_state"); - // get its registry id - int vanillaBlockStateRegistryId = getVanillaBlockStateRegistryId(vanillaBlockStateTag); - // check if another block has occupied the appearance - // TODO blocks share the same look - Key ifAny = this.tempRegistryIdConflictMap.get(vanillaBlockStateRegistryId); - if (ifAny != null && !ifAny.equals(id)) { - throw new LocalizedResourceConfigException("warning.config.block.state.conflict", BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId)).getAsString(), ifAny.toString()); - } - // require models not to be null - Object models = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "models", "model"), "warning.config.block.state.missing_model"); - List variants = ResourceConfigUtils.parseConfigAsList(models, this::getVariantModel); - if (variants.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_model"); - } - // TODO blocks share the same look - this.tempRegistryIdConflictMap.put(vanillaBlockStateRegistryId, id); - // gets the full block state - String blockState = BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId).toString(); - Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); - String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); - // for generating assets - JsonElement combinedVariant = GsonHelper.combine(variants); - this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant); - this.tempVanillaBlockStateModels.put(vanillaBlockStateRegistryId, combinedVariant); - return new VanillaBlockState(blockId, propertyNBT, vanillaBlockStateRegistryId); - } - - public record VanillaBlockState(Key type, String properties, int registryId) { - } - - private JsonObject getVariantModel(Map singleModelMap) { - JsonObject json = new JsonObject(); - String modelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(singleModelMap.get("path"), "warning.config.block.state.model.missing_path"); - if (!ResourceLocation.isValid(modelPath)) { - throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath); - } - json.addProperty("model", modelPath); - if (singleModelMap.containsKey("x")) - json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x")); - if (singleModelMap.containsKey("y")) - json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y")); - if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(singleModelMap.get("uvlock"), "uvlock")); - if (singleModelMap.containsKey("weight")) - json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight")); - Map generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true); - if (generationMap != null) { - prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap)); - } - return json; - } - - private int getVanillaBlockStateRegistryId(String blockState) { - String[] split = blockState.split(":", 3); - if (split.length >= 4) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); - } - int registryId; - String stateOrId = split[split.length - 1]; - boolean isId = !stateOrId.contains("[") && !stateOrId.contains("]"); - if (isId) { - if (split.length == 1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); - } - Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]); - try { - int id = split.length == 2 ? Integer.parseInt(split[1]) : Integer.parseInt(split[2]); - if (id < 0) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); - } - List arranger = this.blockAppearanceArranger.get(block); - if (arranger == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState); - } - if (id >= arranger.size()) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla_id", blockState, String.valueOf(arranger.size() - 1)); - } - registryId = arranger.get(id); - } catch (NumberFormatException e) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", e, blockState); - } - } else { - try { - BlockData blockData = Bukkit.createBlockData(blockState); - registryId = BlockStateUtils.blockDataToId(blockData); - if (!this.blockAppearanceMapper.containsKey(registryId)) { - throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState); - } - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", e, blockState); - } - } - return registryId; - } - private void loadMappingsAndAdditionalBlocks() { this.plugin.logger().info("Loading mappings.yml."); Path mappingsFile = this.plugin.dataFolderPath().resolve("mappings.yml"); @@ -762,13 +533,19 @@ public final class BukkitBlockManager extends AbstractBlockManager { } private LinkedHashMap buildRegisteredRealBlockSlots(Map counter, Map additionalYaml) { - LinkedHashMap map = new LinkedHashMap<>(); - for (Map.Entry entry : counter.entrySet()) { - String id = entry.getKey().toString(); - int additionalStates = (int) additionalYaml.getOrDefault(id, 0); - int internalIds = entry.getValue() + additionalStates; - plugin.logger().info("Loaded " + id + " with " + entry.getValue() + " appearances and " + internalIds + " real block states"); - map.put(entry.getKey(), internalIds); + LinkedHashMap map = new LinkedHashMap<>(counter); + for (Map.Entry entry : additionalYaml.entrySet()) { + Key blockType = Key.of(entry.getKey()); + if (entry.getValue() instanceof Integer i) { + int previous = map.getOrDefault(blockType, 0); + if (previous == 0) { + map.put(blockType, i); + this.plugin.logger().info("Loaded " + blockType + " with " + i + " real block states"); + } else { + map.put(blockType, i + previous); + this.plugin.logger().info("Loaded " + blockType + " with " + previous + " appearances and " + (i + previous) + " real block states"); + } + } } return map; } 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 bb3ef7aaf..e5f42e169 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -2,27 +2,14 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.parser.BlockStateParser; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Location; import org.bukkit.block.data.BlockData; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Minecart; import org.bukkit.entity.Player; -import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; -import org.incendo.cloud.bukkit.parser.location.LocationParser; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; import org.incendo.cloud.parser.standard.IntegerParser; -import org.incendo.cloud.parser.standard.StringParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; public class TestCommand extends BukkitCommandFeature { diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 213fa69b8..c15db1c61 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -267,6 +267,7 @@ warning.config.block.state.bind_failed: "Issue found in file - T warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." warning.config.block.state.model.missing_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_path: "Issue found in file - The block '' has a 'path' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.block.state.model.conflict: "Issue found in file - The block '' is trying to bind model '' to block state '' which has already been bound to model ''" warning.config.block.settings.unknown: "Issue found in file - The block '' is using an unknown setting type ''." warning.config.block.behavior.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for its block behavior." warning.config.block.behavior.invalid_type: "Issue found in file - The block '' is using an invalid block behavior type ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index f67146759..348ab6b22 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -267,6 +267,7 @@ warning.config.block.state.bind_failed: "在文件 发现问题 warning.config.block.state.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 additional-real-blocks.yml 中添加更多真实状态" warning.config.block.state.model.missing_path: "在文件 发现问题 - 方块 '' 的 'model' 缺少必需的 'path' 选项" warning.config.block.state.model.invalid_path: "在文件 发现问题 - 方块 '' 的 'path' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.block.state.model.conflict: "在文件 发现问题 - 方块 '' 正尝试将模型 '' 绑定到方块状态 '' 上, 但是此状态已绑定了另一个模型 ''" warning.config.block.settings.unknown: "在文件 发现问题 - 方块 '' 使用了未知的设置类型 ''" warning.config.block.behavior.missing_type: "在文件 发现问题 - 方块 '' 的行为配置缺少必需的 'type' 参数" warning.config.block.behavior.invalid_type: "在文件 发现问题 - 方块 '' 使用了无效的行为类型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 70dfad312..8b1f9e59d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; @@ -14,6 +15,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; @@ -24,8 +26,10 @@ import org.jetbrains.annotations.NotNull; import java.nio.file.Path; import java.util.*; +import java.util.function.Function; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { + protected final BlockParser blockParser; // CraftEngine objects protected final Map byId = new HashMap<>(); // Cached command suggestions @@ -44,15 +48,19 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Map> blockStateOverrides = new HashMap<>(); // a reverted mapper protected final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); + // client side block tags protected Map> clientBoundTags = Map.of(); protected Map> previousClientBoundTags = Map.of(); // Used to automatically arrange block states for strings such as minecraft:note_block:0 protected Map> blockAppearanceArranger; protected Map> realBlockArranger; + protected Map internalId2StateId; + protected Map registeredBlocks; protected AbstractBlockManager(CraftEngine plugin) { super(plugin); + this.blockParser = new BlockParser(); } @Override @@ -85,8 +93,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } - @Override - public void addBlock(Key id, CustomBlock customBlock) { + protected void addBlockInternal(Key id, CustomBlock customBlock) { this.byId.put(id, customBlock); // generate mod assets if (Config.generateModAssets()) { @@ -96,6 +103,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } + @Override + public ConfigParser parser() { + return this.blockParser; + } + @Override public Map modBlockStates() { return Collections.unmodifiableMap(this.modBlockStates); @@ -148,7 +160,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected abstract int getBlockRegistryId(Key id); - public abstract String stateRegistryIdToStateSNBT(int id); + protected abstract String stateRegistryIdToStateSNBT(int id); + + protected abstract Key getBlockOwnerId(int id); + + protected abstract CustomBlock.Builder platformBuilder(Key id); public class BlockParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; @@ -210,14 +226,56 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 设置参数 properties = Map.of(); appearances = Map.of("", appearanceId); - variants = Map.of("", new BlockStateVariant("", settings, internalId)); + variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockId(internalId, appearanceId))); } // 多方块状态 else { properties = parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances")); - + variants = parseBlockVariants( + ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"), + it -> appearances.getOrDefault(it, -1), settings + ); } + + addBlockInternal(id, platformBuilder(id) + .appearances(appearances) + .variantMapper(variants) + .properties(properties) + .settings(settings) + .lootTable(LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot"))) + .behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))) + .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) + .build()); + } + + private Map parseBlockVariants(Map variantsSection, + Function appearanceValidator, + BlockSettings parentSettings) { + Map variants = new HashMap<>(); + for (Map.Entry entry : variantsSection.entrySet()) { + Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + String variantNBT = entry.getKey(); + String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); + int appearanceId = appearanceValidator.apply(appearance); + if (appearanceId == -1) { + throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); + } + int internalId = getInternalBlockId(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"), appearanceId); + Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); + variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalId)); + } + return variants; + } + + private int getInternalBlockId(int internalId, int appearanceId) { + Key baseBlock = getBlockOwnerId(appearanceId); + Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId); + int internalBlockRegistryId = Optional.ofNullable(AbstractBlockManager.this.internalId2StateId.get(internalBlockId)).orElse(-1); + if (internalBlockRegistryId == -1) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1)); + } + return internalBlockRegistryId; } private Map parseBlockAppearances(Map appearancesSection) { @@ -265,11 +323,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); // 结合variants JsonElement combinedVariant = GsonHelper.combine(variants); - JsonElement previous = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant); + Map overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()); + JsonElement previous = overrideMap.get(propertyNBT); if (previous != null && !previous.equals(combinedVariant)) { - // todo 播报可能的冲突 - plugin.logger().warn("warning 1"); + throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous)); } + overrideMap.put(propertyNBT, combinedVariant); } private JsonObject parseAppearanceModelSectionAsJson(Map section) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index cc2c8b02e..e524b86c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -64,6 +64,10 @@ public abstract class AbstractCustomBlock implements CustomBlock { if (tag == null) { throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); } + List possibleStates = this.getPossibleStates(tag); + if (possibleStates.size() != 1) { + throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); + } BlockStateVariant blockStateVariant = entry.getValue(); int vanillaStateRegistryId = appearances.getOrDefault(blockStateVariant.appearance(), -1); // This should never happen @@ -71,15 +75,14 @@ public abstract class AbstractCustomBlock implements CustomBlock { vanillaStateRegistryId = appearances.values().iterator().next(); } // Late init states - for (ImmutableBlockState state : this.getPossibleStates(tag)) { - state.setBehavior(this.behavior); - state.setSettings(blockStateVariant.settings()); - state.setVanillaBlockState((BlockStateWrapper.VanillaBlockState) BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId)); - state.setCustomBlockState((BlockStateWrapper.CustomBlockState) BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId())); - } + ImmutableBlockState state = possibleStates.getFirst(); + state.setSettings(blockStateVariant.settings()); + state.setVanillaBlockState((BlockStateWrapper.VanillaBlockState) BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId)); + state.setCustomBlockState((BlockStateWrapper.CustomBlockState) BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId())); } // double check if there's any invalid state for (ImmutableBlockState state : this.variantProvider().states()) { + state.setBehavior(this.behavior); if (state.settings() == null) { state.setSettings(settings); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 0319ecfd9..6b69f04ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -28,8 +28,6 @@ public interface BlockManager extends Manageable, ModelGenerator { Optional blockById(Key key); - void addBlock(Key id, CustomBlock customBlock); - Collection cachedSuggestions(); Map soundMapper(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java index b6a52e91d..d5cfdd402 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/PDCModifier.java @@ -6,13 +6,10 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; -import java.util.List; import java.util.Map; import java.util.Optional; 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 d0d69ebc7..9f240f7dd 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 @@ -212,4 +212,15 @@ public final class ResourceConfigUtils { } throw new LocalizedResourceConfigException("warning.config.type.map", String.valueOf(obj), option); } + + @SuppressWarnings("unchecked") + public static Map getAsMapOrNull(Object obj, String option) { + if (obj == null) { + return null; + } + if (obj instanceof Map map) { + return (Map) map; + } + throw new LocalizedResourceConfigException("warning.config.type.map", String.valueOf(obj), option); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java index e5f704471..211addb11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java @@ -16,7 +16,10 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.IntUnaryOperator; +import java.util.function.Predicate; import java.util.stream.LongStream; public class PalettedContainer implements PaletteResizeListener, ReadableContainer { From 276550d478a3274c04a779e63947a5de9467ee98 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 22:03:08 +0800 Subject: [PATCH 52/57] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E5=8C=BA=E5=9D=97=E5=8A=A0=E8=BD=BD=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/world/BukkitWorldManager.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 7d557cd21..fd9ac0846 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 @@ -54,6 +54,9 @@ public class BukkitWorldManager implements WorldManager, Listener { this.plugin = plugin; this.worlds = new HashMap<>(); this.storageAdaptor = new DefaultStorageAdaptor(); + for (World world : Bukkit.getWorlds()) { + this.worlds.put(world.getUID(), new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor)); + } } @Override @@ -98,7 +101,6 @@ public class BukkitWorldManager implements WorldManager, Listener { public void delayedInit() { // events and tasks - Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin()); this.tickTask = this.plugin.scheduler().asyncRepeating(() -> { try { if (this.isTicking) { @@ -117,9 +119,7 @@ public class BukkitWorldManager implements WorldManager, Listener { try { for (World world : Bukkit.getWorlds()) { try { - CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor); - this.worlds.put(world.getUID(), ceWorld); - this.resetWorldArray(); + CEWorld ceWorld = this.worlds.computeIfAbsent(world.getUID(), k -> new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor)); for (Chunk chunk : world.getLoadedChunks()) { handleChunkLoad(ceWorld, chunk); } @@ -127,9 +127,11 @@ public class BukkitWorldManager implements WorldManager, Listener { CraftEngine.instance().logger().warn("Error loading world: " + world.getName(), e); } } + this.resetWorldArray(); } finally { this.worldMapLock.writeLock().unlock(); } + Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin()); } @Override @@ -246,6 +248,7 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onChunkLoad(ChunkLoadEvent event) { + if (!this.fullyLoaded) return; this.worldMapLock.readLock().lock(); CEWorld world; try { @@ -261,6 +264,7 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onChunkUnload(ChunkUnloadEvent event) { + if (!this.fullyLoaded) return; CEWorld world; this.worldMapLock.readLock().lock(); try { From 01307f88bd3189faf8b07b2827022a81df6832a3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 22:03:22 +0800 Subject: [PATCH 53/57] Update BukkitWorldManager.java --- .../momirealms/craftengine/bukkit/world/BukkitWorldManager.java | 2 -- 1 file changed, 2 deletions(-) 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 fd9ac0846..ebad6e525 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 @@ -248,7 +248,6 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onChunkLoad(ChunkLoadEvent event) { - if (!this.fullyLoaded) return; this.worldMapLock.readLock().lock(); CEWorld world; try { @@ -264,7 +263,6 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onChunkUnload(ChunkUnloadEvent event) { - if (!this.fullyLoaded) return; CEWorld world; this.worldMapLock.readLock().lock(); try { From 1f92052ae12e0bb8024b0dbdddadfa4b07b3cdde Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 22:22:10 +0800 Subject: [PATCH 54/57] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=9B=E4=B8=96?= =?UTF-8?q?=E7=A5=9E=E5=85=BC=E5=AE=B9=E6=97=B6=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) 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 a341e41fe..636924df9 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 @@ -39,8 +39,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map modelProviders; private final Map levelerProviders; private boolean hasPlaceholderAPI; - private boolean hasViaVersion; - private MythicSkillHelper skillExecute; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -63,33 +61,13 @@ public class BukkitCompatibilityManager implements CompatibilityManager { this.hasPlaceholderAPI = true; logHook("PlaceholderAPI"); } - // skript if (this.isPluginEnabled("Skript")) { SkriptHook.register(); logHook("Skript"); - Plugin skriptPlugin = getPlugin("Skript"); - // This can cause bugs, needs to find a better way -// for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) { -// if (task.getOwner() == skriptPlugin) { -// task.cancel(); -// if (VersionHelper.isFolia()) { -// Bukkit.getGlobalRegionScheduler().run(skriptPlugin, (t) -> { -// FastNMS.INSTANCE.getBukkitTaskRunnable(task).run(); -// }); -// } else { -// Bukkit.getScheduler().runTask(skriptPlugin, FastNMS.INSTANCE.getBukkitTaskRunnable(task)); -// } -// } -// } } // WorldEdit if (this.isPluginEnabled("FastAsyncWorldEdit")) { - try { - this.initFastAsyncWorldEditHook(); - logHook("FastAsyncWorldEdit"); - } catch (Exception e) { - this.plugin.logger().warn("[Compatibility] Failed to initialize FastAsyncWorldEdit hook", e); - } + // do nothing } else if (this.isPluginEnabled("WorldEdit")) { this.initWorldEditHook(); logHook("WorldEdit"); @@ -136,6 +114,15 @@ public class BukkitCompatibilityManager implements CompatibilityManager { new MythicItemDropListener(this.plugin); logHook("MythicMobs"); } + // FastAsyncWorldEdit + if (this.isPluginEnabled("FastAsyncWorldEdit")) { + try { + this.initFastAsyncWorldEditHook(); + logHook("FastAsyncWorldEdit"); + } catch (Exception e) { + this.plugin.logger().warn("[Compatibility] Failed to initialize FastAsyncWorldEdit hook", e); + } + } } @Override From 1b564b6321c034e59eaf20e535d6ca3f6ca9ec3a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 22:23:01 +0800 Subject: [PATCH 55/57] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BF=BD=E7=95=A5?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=9A=84MM=E6=8E=89=E8=90=BD=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/mythicmobs/MythicItemDropListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java index 96cacc0b7..5b616b7fd 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDropListener.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class MythicItemDropListener implements Listener { @@ -16,7 +17,7 @@ public class MythicItemDropListener implements Listener { Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); } - @EventHandler + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) public void onMythicDropLoad(MythicDropLoadEvent event) { if (!event.getDropName().equalsIgnoreCase("craftengine")) return; String argument = event.getArgument(); From 128bdb60452c30b518bf25eb08832b3d678b3133 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 20 Aug 2025 23:19:44 +0800 Subject: [PATCH 56/57] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=8C=96=E6=8E=98?= =?UTF-8?q?=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/user/BukkitServerPlayer.java | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) 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 523e9cd92..243911557 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 @@ -470,7 +470,21 @@ public class BukkitServerPlayer extends Player { @Override public float getDestroyProgress(Object blockState, BlockPos pos) { - return FastNMS.INSTANCE.method$BlockStateBase$getDestroyProgress(blockState, serverPlayer(), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformPlayer().getWorld()), LocationUtils.toBlockPos(pos)); + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState); + float progress = FastNMS.INSTANCE.method$BlockStateBase$getDestroyProgress(blockState, serverPlayer(), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformPlayer().getWorld()), LocationUtils.toBlockPos(pos)); + if (optionalCustomState.isPresent()) { + ImmutableBlockState customState = optionalCustomState.get(); + Item tool = getItemInHand(InteractionHand.MAIN_HAND); + boolean isCorrectTool = FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(tool.getLiteralObject(), blockState); + // 如果自定义方块在服务端侧未使用正确地工具,那么需要还原挖掘速度 + if (!isCorrectTool) { + progress *= (10f / 3f); + } + if (!BlockStateUtils.isCorrectTool(customState, tool)) { + progress *= customState.settings().incorrectToolSpeed(); + } + } + return progress; } private void predictNextBlockToMine() { @@ -655,28 +669,6 @@ public class BukkitServerPlayer extends Player { // double check custom block if (optionalCustomState.isPresent()) { ImmutableBlockState customState = optionalCustomState.get(); - BlockSettings blockSettings = customState.settings(); - if (blockSettings.requireCorrectTool()) { - if (!item.isEmpty()) { - // it's correct on plugin side - if (blockSettings.isCorrectTool(item.id())) { - // but not on serverside - if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { - // we fix the speed - progressToAdd = progressToAdd * (10f / 3f); - } - } else { - // not a correct tool on plugin side and not a correct tool on serverside - if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { - progressToAdd = progressToAdd * (10f / 3f) * blockSettings.incorrectToolSpeed(); - } - } - } else { - // item is null, but it requires correct tool, then we reset the speed - progressToAdd = progressToAdd * (10f / 3f) * blockSettings.incorrectToolSpeed(); - } - } - // accumulate progress this.miningProgress = progressToAdd + miningProgress; int packetStage = (int) (this.miningProgress * 10.0F); From 8157ad3099aac428f0c5ae74829567fb434f7669 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 21 Aug 2025 21:01:05 +0800 Subject: [PATCH 57/57] 0.0.62 --- .../BukkitCompatibilityManager.java | 17 +++++++---------- .../worldedit/FastAsyncWorldEditDelegate.java | 1 + .../bukkit/plugin/user/BukkitServerPlayer.java | 1 - .../bukkit/world/BukkitWorldManager.java | 6 ++++++ gradle.properties | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) 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 636924df9..5e752460f 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 @@ -66,8 +66,14 @@ public class BukkitCompatibilityManager implements CompatibilityManager { logHook("Skript"); } // WorldEdit + // FastAsyncWorldEdit if (this.isPluginEnabled("FastAsyncWorldEdit")) { - // do nothing + try { + this.initFastAsyncWorldEditHook(); + logHook("FastAsyncWorldEdit"); + } catch (Exception e) { + this.plugin.logger().warn("[Compatibility] Failed to initialize FastAsyncWorldEdit hook", e); + } } else if (this.isPluginEnabled("WorldEdit")) { this.initWorldEditHook(); logHook("WorldEdit"); @@ -114,15 +120,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { new MythicItemDropListener(this.plugin); logHook("MythicMobs"); } - // FastAsyncWorldEdit - if (this.isPluginEnabled("FastAsyncWorldEdit")) { - try { - this.initFastAsyncWorldEditHook(); - logHook("FastAsyncWorldEdit"); - } catch (Exception e) { - this.plugin.logger().warn("[Compatibility] Failed to initialize FastAsyncWorldEdit hook", e); - } - } } @Override 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 014f81d63..04401240e 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 @@ -85,6 +85,7 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { @SuppressWarnings("unused") public void onEditSessionEvent(EditSessionEvent event) { if (event.getWorld() == null || event.getStage() != EditSession.Stage.BEFORE_CHANGE) return; + if (!BukkitWorldManager.instance().initialized()) return; event.setExtent(new FastAsyncWorldEditDelegate(event, event.getExtent())); } }); 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 243911557..bf6afab4b 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 @@ -18,7 +18,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MMobEffects import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.block.BlockSettings; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.GameMode; 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 ebad6e525..45d45bf9d 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 @@ -48,6 +48,7 @@ public class BukkitWorldManager implements WorldManager, Listener { private CEWorld lastVisitedWorld; private StorageAdaptor storageAdaptor; private boolean isTicking = false; + private boolean initialized = false; public BukkitWorldManager(BukkitCraftEngine plugin) { instance = this; @@ -132,6 +133,7 @@ public class BukkitWorldManager implements WorldManager, Listener { this.worldMapLock.writeLock().unlock(); } Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin()); + this.initialized = true; } @Override @@ -237,6 +239,10 @@ public class BukkitWorldManager implements WorldManager, Listener { } } + public boolean initialized() { + return initialized; + } + @Override public net.momirealms.craftengine.core.world.World wrap(T world) { if (world instanceof World w) { diff --git a/gradle.properties b/gradle.properties index 564230f8d..3ce89d0df 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.61.10 +project_version=0.0.62 config_version=44 lang_version=24 project_group=net.momirealms