You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bukkit物品比较时如何忽略属性修饰符UUID完成相似判断

问题原因

ItemStack#isSimilar() 做物品一致性比对时,会将属性修饰符(AttributeModifier)的UUID作为必校验字段。你代码中创建AttributeModifier时调用的是不传入UUID的构造方法,该构造方法会自动生成随机UUID,每次调用item()生成的新物品属性UUID都完全不同,自然无法和玩家手持的物品通过isSimilar()校验。

解决方案

方案1:为属性修饰符指定固定UUID(推荐,零侵入适配现有逻辑)

创建AttributeModifier时手动传入固定的UUID实例,只要两个物品的属性类型、修饰符UUID、名称、数值、运算规则完全一致,isSimilar()就能正常通过校验,不需要修改原有比对逻辑。
修改后的代码如下:

// 全局定义固定UUID,不要在生成物品的方法内重复创建
public static final UUID MODIFIER_UUID_ATTACK_DAMAGE = UUID.fromString("a616aa14-b86c-43a0-b00d-e4ee39a6a1c2");
public static final UUID MODIFIER_UUID_ATTACK_SPEED = UUID.fromString("28730ac1-7b0f-4d39-9e3a-7d23c943c7d8");

public static ItemStack item() {
    ItemStack item = new ItemStack(Material.STICK);
    ItemMeta meta = item.getItemMeta();

    meta.setDisplayName("§2§lCool sword");
    // 传入固定UUID构造属性修饰符
    meta.addAttributeModifier(Attribute.GENERIC_ATTACK_DAMAGE, 
            new AttributeModifier(MODIFIER_UUID_ATTACK_DAMAGE, "generic.attackDamage", 11.0, AttributeModifier.Operation.ADD_NUMBER));
    meta.addAttributeModifier(Attribute.GENERIC_ATTACK_SPEED, 
            new AttributeModifier(MODIFIER_UUID_ATTACK_SPEED, "generic.attackSpeed", 1.4, AttributeModifier.Operation.ADD_NUMBER));
    meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
    item.setItemMeta(meta);

    return item;
}

注意:原代码中item()方法返回值为Object类型,这里直接调整为返回ItemStack,省去后续不必要的强转,避免类型转换异常。

方案2:自定义物品比对逻辑(适配无固定UUID的场景)

如果你的业务场景无法保证同配置物品的属性UUID完全一致,可以自行实现比对逻辑,跳过UUID校验,仅比对属性的核心特征(名称、数值、运算类型、生效槽位)即可。
核心实现参考:

public static boolean isSameCustomItem(ItemStack a, ItemStack b) {
    // 基础属性前置校验
    if (a == null || b == null) return a == b;
    if (a.getType() != b.getType()) return false;
    ItemMeta metaA = a.getItemMeta();
    ItemMeta metaB = b.getItemMeta();
    if (metaA == null || metaB == null) return metaA == metaB;
    if (!metaA.getDisplayName().equals(metaB.getDisplayName())) return false;
    if (!metaA.getItemFlags().equals(metaB.getItemFlags())) return false;

    // 跳过UUID比对属性修饰符
    for (Attribute attribute : Attribute.values()) {
        Collection<AttributeModifier> modsA = metaA.getAttributeModifiers(attribute);
        Collection<AttributeModifier> modsB = metaB.getAttributeModifiers(attribute);
        if (modsA == null && modsB == null) continue;
        if (modsA == null || modsB == null || modsA.size() != modsB.size()) return false;

        // 提取修饰符核心特征做比对
        List<AttributeModifierEntry> entriesA = modsA.stream()
                .map(mod -> new AttributeModifierEntry(mod.getName(), mod.getAmount(), mod.getOperation(), mod.getSlot()))
                .toList();
        List<AttributeModifierEntry> entriesB = modsB.stream()
                .map(mod -> new AttributeModifierEntry(mod.getName(), mod.getAmount(), mod.getOperation(), mod.getSlot()))
                .toList();
        if (!entriesA.containsAll(entriesB)) return false;
    }
    return true;
}

// 用于比对属性特征的记录类
record AttributeModifierEntry(String name, double amount, AttributeModifier.Operation op, EquipmentSlot slot) {}

使用时将原有processEvent方法中的isSimilar替换为自定义方法即可:

public static void processEvent(Entity damager, LivingEntity entity) {
    if (!(damager instanceof Player)) return;
    Player player = (Player) damager;

    if (!isSameCustomItem(player.getItemInHand(), item())) return;

    entity.addPotionEffect(new PotionEffect(PotionEffectType.GLOWING,200, 1, true, false));
}

补充:Minecraft原版物品的属性修饰符均使用固定UUID,随机UUID是插件调用无UUID参数的构造方法时自动生成的。使用固定UUID是服务端插件开发的通用最佳实践,除了解决比对问题外,还能避免属性重复生效、和其他插件属性冲突的兼容性问题。

内容的提问来源于stack exchange,提问作者Miskakao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:57:54