From 465eebe15aba61b00d8c13e08a4bb490be20ac56 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 6 Dec 2025 00:58:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=98=BE=E7=A4=BA=E6=8E=89?= =?UTF-8?q?=E8=90=BD=E7=89=A9=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../handler/CommonItemPacketHandler.java | 68 ++++++++++++++++++- common-files/src/main/resources/config.yml | 4 ++ .../craftengine/core/item/ItemSettings.java | 38 +++++++++++ .../core/plugin/config/Config.java | 12 ++++ .../text/minimessage/CustomTagResolver.java | 34 ++++++++++ .../core/util/LegacyChatFormatter.java | 26 +++++++ 7 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/CustomTagResolver.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/LegacyChatFormatter.java diff --git a/README.md b/README.md index 2f45c4583..1780802cf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.65") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.65") + compileOnly("net.momirealms:craft-engine-core:0.0.66") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.66") } ``` \ No newline at end of file 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 f9b57d6d3..0afd02080 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 @@ -1,19 +1,33 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.ItemEntityData; 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.ComponentUtils; import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; +import net.momirealms.craftengine.core.plugin.text.minimessage.CustomTagResolver; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.ArrayUtils; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Map; import java.util.Optional; public class CommonItemPacketHandler implements EntityPacketHandler { @@ -27,11 +41,14 @@ public class CommonItemPacketHandler implements EntityPacketHandler { int id = buf.readVarInt(); boolean changed = false; List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + Component nameToShow = null; 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.UNSAFE_ITEM_DATA_ID) continue; Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + + // 可能是其他插件导致的问题 if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { long time = System.currentTimeMillis(); if (time - lastWarningTime > 5000) { @@ -42,15 +59,64 @@ public class CommonItemPacketHandler implements EntityPacketHandler { } continue; } + + // 处理 drop-display 物品设置 ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + Optional> optionalCustomItem = wrappedItem.getCustomItem(); + String showName = null; + if (optionalCustomItem.isPresent()) { + showName = optionalCustomItem.get().settings().dropDisplay(); + } else if (Config.enableDefaultDropDisplay()) { + showName = Config.defaultDropDisplayFormat(); + } + + // 如果设定了自定义展示名 + if (showName != null) { + PlayerOptionalContext context = NetworkTextReplaceContext.of(user, ContextHolder.builder() + .withParameter(DirectContextParameters.COUNT, itemStack.getAmount())); + Optional optionalHoverComponent = wrappedItem.hoverNameComponent(); + Component hoverComponent; + if (optionalHoverComponent.isPresent()) { + Map tokens = CraftEngine.instance().fontManager().matchTags(AdventureHelper.componentToNbt(optionalHoverComponent.get())); + if (tokens.isEmpty()) { + hoverComponent = optionalHoverComponent.get(); + } else { + hoverComponent = AdventureHelper.replaceText(optionalHoverComponent.get(), tokens, context); + } + } else { + hoverComponent = Component.translatable(itemStack.translationKey()); + } + // 展示名称为空,则显示其hover name + if (showName.isEmpty()) { + nameToShow = hoverComponent; + } + // 显示自定义格式的名字 + else { + nameToShow = AdventureHelper.miniMessage().deserialize( + showName, + ArrayUtils.appendElementToArrayTail(context.tagResolvers(), new CustomTagResolver("name", hoverComponent)) + ); + } + } + + // 转换为客户端侧物品 Optional optional = BukkitItemManager.instance().s2c(itemStack, user); - if (optional.isEmpty()) continue; + if (optional.isEmpty()) { + break; + } changed = true; itemStack = optional.get(); Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack))); break; } + // 添加自定义显示名 + if (nameToShow != null) { + changed = true; + packedItems.add(ItemEntityData.CustomNameVisible.createEntityData(true)); + packedItems.add(ItemEntityData.CustomName.createEntityData(Optional.of(ComponentUtils.adventureToMinecraft(nameToShow)))); + } if (changed) { event.setChanged(true); buf.clear(); diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 64b7eef86..26716aa71 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -250,6 +250,10 @@ item: default: 10000 overrides: paper: 20000 + # Toggle whether to display the names of dropped items by default and configure the display format. This setting can be overridden for individual items. + default-drop-display: + enable: false + format: "x " equipment: # The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims) diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index 00c6601a2..ed04a975e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -49,6 +49,10 @@ public class ItemSettings { Color fireworkColor; float keepOnDeathChance = 0f; float destroyOnDeathChance = 0f; + @Nullable + String dropDisplay = Config.defaultDropDisplayFormat(); + @Nullable + LegacyChatFormatter glowColor = null; Map, Object> customData = new IdentityHashMap<>(4); private ItemSettings() {} @@ -113,6 +117,8 @@ public class ItemSettings { newSettings.ingredientSubstitutes = settings.ingredientSubstitutes; newSettings.keepOnDeathChance = settings.keepOnDeathChance; newSettings.destroyOnDeathChance = settings.destroyOnDeathChance; + newSettings.glowColor = settings.glowColor; + newSettings.dropDisplay = settings.dropDisplay; newSettings.customData = new IdentityHashMap<>(settings.customData); return newSettings; } @@ -243,6 +249,16 @@ public class ItemSettings { return this.destroyOnDeathChance; } + @Nullable + public LegacyChatFormatter glowColor() { + return this.glowColor; + } + + @Nullable + public String dropDisplay() { + return this.dropDisplay; + } + public ItemSettings fireworkColor(Color color) { this.fireworkColor = color; return this; @@ -293,6 +309,11 @@ public class ItemSettings { return this; } + public ItemSettings dropDisplay(String showName) { + this.dropDisplay = showName; + return this; + } + public ItemSettings projectileMeta(ProjectileMeta projectileMeta) { this.projectileMeta = projectileMeta; return this; @@ -353,6 +374,11 @@ public class ItemSettings { return this; } + public ItemSettings glowColor(LegacyChatFormatter chatFormatter) { + this.glowColor = chatFormatter; + return this; + } + @FunctionalInterface public interface Modifier { @@ -395,6 +421,18 @@ public class ItemSettings { boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable"); return settings -> settings.renameable(bool); })); + registerFactory("drop-display", (value -> { + if (value instanceof String name) { + return settings -> settings.dropDisplay(name); + } else { + boolean bool = ResourceConfigUtils.getAsBoolean(value, "drop-display"); + return settings -> settings.dropDisplay(bool ? "" : null); + } + })); + registerFactory("glow-color", (value -> { + LegacyChatFormatter chatFormatter = ResourceConfigUtils.getAsEnum(value, LegacyChatFormatter.class, LegacyChatFormatter.WHITE); + return settings -> settings.glowColor(chatFormatter); + })); registerFactory("anvil-repair-item", (value -> { List anvilRepairItemList = ResourceConfigUtils.parseConfigAsList(value, material -> { int amount = ResourceConfigUtils.getAsInt(material.getOrDefault("amount", 0), "amount"); 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 df09a8b08..a00dc1f0e 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 @@ -193,6 +193,8 @@ public class Config { protected Map item$custom_model_data_starting_value$overrides; protected boolean item$always_use_item_model; protected String item$default_material = ""; + protected boolean item$default_drop_display$enable = false; + protected String item$default_drop_display$format = null; protected String equipment$sacrificed_vanilla_armor$type; protected Key equipment$sacrificed_vanilla_armor$asset_id; @@ -471,6 +473,8 @@ public class Config { item$custom_model_data_starting_value$default = config.getInt("item.custom-model-data-starting-value.default", 10000); item$always_use_item_model = config.getBoolean("item.always-use-item-model", true) && VersionHelper.isOrAbove1_21_2(); item$default_material = config.getString("item.default-material", ""); + item$default_drop_display$enable = config.getBoolean("item.default-drop-display.enable", false); + item$default_drop_display$format = item$default_drop_display$enable ? config.getString("item.default-drop-display.format", "x "): null; Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides"); if (customModelDataOverridesSection != null) { @@ -1175,6 +1179,14 @@ public class Config { return instance.resource_pack$optimization$texture$zopfli_iterations; } + public static boolean enableDefaultDropDisplay() { + return instance.item$default_drop_display$enable; + } + + public static String defaultDropDisplayFormat() { + return instance.item$default_drop_display$format; + } + public static boolean enableEntityCulling() { return instance.client_optimization$entity_culling$enable; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/CustomTagResolver.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/CustomTagResolver.java new file mode 100644 index 000000000..1d66bf4d7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/CustomTagResolver.java @@ -0,0 +1,34 @@ +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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CustomTagResolver implements TagResolver { + private final String name; + private final Component replacement; + + public CustomTagResolver(String name, Component replacement) { + this.name = name; + this.replacement = replacement; + } + + @Override + @Nullable + public Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull Context ctx) throws ParsingException { + if (!has(name)) { + return null; + } + return Tag.selfClosingInserting(this.replacement); + } + + @Override + public boolean has(@NotNull String name) { + return this.name.equals(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/LegacyChatFormatter.java b/core/src/main/java/net/momirealms/craftengine/core/util/LegacyChatFormatter.java new file mode 100644 index 000000000..5f71615ca --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/LegacyChatFormatter.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.core.util; + +public enum LegacyChatFormatter { + BLACK, + DARK_BLUE, + DARK_GREEN, + DARK_AQUA, + DARK_RED, + DARK_PURPLE, + GOLD, + GRAY, + DARK_GRAY, + BLUE, + GREEN, + AQUA, + RED, + LIGHT_PURPLE, + YELLOW, + WHITE, + OBFUSCATED, + BOLD, + STRIKETHROUGH, + UNDERLINE, + ITALIC, + RESET; +}