9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

添加显示掉落物名称

This commit is contained in:
XiaoMoMi
2025-12-06 00:58:17 +08:00
parent 5395dc4ea9
commit 465eebe15a
7 changed files with 183 additions and 3 deletions

View File

@@ -75,7 +75,7 @@ repositories {
``` ```
```kotlin ```kotlin
dependencies { dependencies {
compileOnly("net.momirealms:craft-engine-core:0.0.65") compileOnly("net.momirealms:craft-engine-core:0.0.66")
compileOnly("net.momirealms:craft-engine-bukkit:0.0.65") compileOnly("net.momirealms:craft-engine-bukkit:0.0.66")
} }
``` ```

View File

@@ -1,19 +1,33 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler; 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.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; 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.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.entity.player.Player; 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.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config; 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.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; 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 net.momirealms.craftengine.core.util.FriendlyByteBuf;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
public class CommonItemPacketHandler implements EntityPacketHandler { public class CommonItemPacketHandler implements EntityPacketHandler {
@@ -27,11 +41,14 @@ public class CommonItemPacketHandler implements EntityPacketHandler {
int id = buf.readVarInt(); int id = buf.readVarInt();
boolean changed = false; boolean changed = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
Component nameToShow = null;
for (int i = 0; i < packedItems.size(); i++) { for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i); Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.UNSAFE_ITEM_DATA_ID) continue; if (entityDataId != EntityDataUtils.UNSAFE_ITEM_DATA_ID) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
// 可能是其他插件导致的问题
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (time - lastWarningTime > 5000) { if (time - lastWarningTime > 5000) {
@@ -42,15 +59,64 @@ public class CommonItemPacketHandler implements EntityPacketHandler {
} }
continue; continue;
} }
// 处理 drop-display 物品设置
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
Optional<CustomItem<ItemStack>> 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<Component> optionalHoverComponent = wrappedItem.hoverNameComponent();
Component hoverComponent;
if (optionalHoverComponent.isPresent()) {
Map<String, ComponentProvider> 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<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, user); Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, user);
if (optional.isEmpty()) continue; if (optional.isEmpty()) {
break;
}
changed = true; changed = true;
itemStack = optional.get(); itemStack = optional.get();
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); 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))); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)));
break; break;
} }
// 添加自定义显示名
if (nameToShow != null) {
changed = true;
packedItems.add(ItemEntityData.CustomNameVisible.createEntityData(true));
packedItems.add(ItemEntityData.CustomName.createEntityData(Optional.of(ComponentUtils.adventureToMinecraft(nameToShow))));
}
if (changed) { if (changed) {
event.setChanged(true); event.setChanged(true);
buf.clear(); buf.clear();

View File

@@ -250,6 +250,10 @@ item:
default: 10000 default: 10000
overrides: overrides:
paper: 20000 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: "<arg:count>x <name>"
equipment: equipment:
# The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims) # The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims)

View File

@@ -49,6 +49,10 @@ public class ItemSettings {
Color fireworkColor; Color fireworkColor;
float keepOnDeathChance = 0f; float keepOnDeathChance = 0f;
float destroyOnDeathChance = 0f; float destroyOnDeathChance = 0f;
@Nullable
String dropDisplay = Config.defaultDropDisplayFormat();
@Nullable
LegacyChatFormatter glowColor = null;
Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4); Map<CustomDataType<?>, Object> customData = new IdentityHashMap<>(4);
private ItemSettings() {} private ItemSettings() {}
@@ -113,6 +117,8 @@ public class ItemSettings {
newSettings.ingredientSubstitutes = settings.ingredientSubstitutes; newSettings.ingredientSubstitutes = settings.ingredientSubstitutes;
newSettings.keepOnDeathChance = settings.keepOnDeathChance; newSettings.keepOnDeathChance = settings.keepOnDeathChance;
newSettings.destroyOnDeathChance = settings.destroyOnDeathChance; newSettings.destroyOnDeathChance = settings.destroyOnDeathChance;
newSettings.glowColor = settings.glowColor;
newSettings.dropDisplay = settings.dropDisplay;
newSettings.customData = new IdentityHashMap<>(settings.customData); newSettings.customData = new IdentityHashMap<>(settings.customData);
return newSettings; return newSettings;
} }
@@ -243,6 +249,16 @@ public class ItemSettings {
return this.destroyOnDeathChance; return this.destroyOnDeathChance;
} }
@Nullable
public LegacyChatFormatter glowColor() {
return this.glowColor;
}
@Nullable
public String dropDisplay() {
return this.dropDisplay;
}
public ItemSettings fireworkColor(Color color) { public ItemSettings fireworkColor(Color color) {
this.fireworkColor = color; this.fireworkColor = color;
return this; return this;
@@ -293,6 +309,11 @@ public class ItemSettings {
return this; return this;
} }
public ItemSettings dropDisplay(String showName) {
this.dropDisplay = showName;
return this;
}
public ItemSettings projectileMeta(ProjectileMeta projectileMeta) { public ItemSettings projectileMeta(ProjectileMeta projectileMeta) {
this.projectileMeta = projectileMeta; this.projectileMeta = projectileMeta;
return this; return this;
@@ -353,6 +374,11 @@ public class ItemSettings {
return this; return this;
} }
public ItemSettings glowColor(LegacyChatFormatter chatFormatter) {
this.glowColor = chatFormatter;
return this;
}
@FunctionalInterface @FunctionalInterface
public interface Modifier { public interface Modifier {
@@ -395,6 +421,18 @@ public class ItemSettings {
boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable"); boolean bool = ResourceConfigUtils.getAsBoolean(value, "renameable");
return settings -> settings.renameable(bool); 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 -> { registerFactory("anvil-repair-item", (value -> {
List<AnvilRepairItem> anvilRepairItemList = ResourceConfigUtils.parseConfigAsList(value, material -> { List<AnvilRepairItem> anvilRepairItemList = ResourceConfigUtils.parseConfigAsList(value, material -> {
int amount = ResourceConfigUtils.getAsInt(material.getOrDefault("amount", 0), "amount"); int amount = ResourceConfigUtils.getAsInt(material.getOrDefault("amount", 0), "amount");

View File

@@ -193,6 +193,8 @@ public class Config {
protected Map<Key, Integer> item$custom_model_data_starting_value$overrides; protected Map<Key, Integer> item$custom_model_data_starting_value$overrides;
protected boolean item$always_use_item_model; protected boolean item$always_use_item_model;
protected String item$default_material = ""; 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 String equipment$sacrificed_vanilla_armor$type;
protected Key equipment$sacrificed_vanilla_armor$asset_id; 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$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$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_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", "<arg:count>x <name>"): null;
Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides"); Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides");
if (customModelDataOverridesSection != null) { if (customModelDataOverridesSection != null) {
@@ -1175,6 +1179,14 @@ public class Config {
return instance.resource_pack$optimization$texture$zopfli_iterations; 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() { public static boolean enableEntityCulling() {
return instance.client_optimization$entity_culling$enable; return instance.client_optimization$entity_culling$enable;
} }

View File

@@ -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);
}
}

View File

@@ -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;
}