创建你属于自己的属性

又称 "如何属性Oraxen?"

技能是如何运转的?

属性是什么?

技能是一个自定义的物品属性。同一属性在不同的物品上可以有不同的变化。例如,耐久属性允许您为一个物品定义一个自定义的耐久,但并不是所有拥有耐久机制的物品都有相同的耐久

耐久机制的工作原理是将物品的耐久存储在它的metadatas中,并使用耐久度条来显示它的自定义耐久度,而不是它的真正耐久度

那么如果每个项目的属性都不一样,我是不是每次都要重写一个不同的耐久呢?

当然,为此Oraxen允许你为每个属性关联一个ItemModifier列表。ItemModifier是Function,它基本上是一小段代码,包含了当一个物品由服务器通过其配置生成时要对其进行的修改。例如对于耐久机制,我使用了一个 itemModifier,它可以将用户选择的耐久存储在物品的 metadatas 中

item -> item.setCustomTag(NAMESPACED_KEY,
                        PersistentDataType.INTEGER, section.getInt("value"))

让我们创建我们的第一个属性

在本教程中,我将以耐久机制为例(因为它非常简单易懂),但你可以按照本教程来创建你想要的机制

第一步:创建我们的属性类

从创建一个继承自Mechanical的类开始,如果使用intelliJ,则应该得到如下所示:

class DurabilityMechanic extends Mechanic {

    public DurabilityMechanic(MechanicFactory mechanicFactory, 
                    ConfigurationSection section,
                    Function<ItemBuilder, ItemBuilder>... modifiers) {
        super(mechanicFactory, section, modifiers);
    }

}

Mechanic构造函数需要三个参数:

- 创建属性的实例
- 用于配置属性的部分
- 项目修饰

我希望我的属性文件的每个变化都有不同的耐久,所以我将阅读属性文件的配置并存储值

属性配置部分的外观:

class DurabilityMechanic extends Mechanic {

    private int itemDurability;

    public DurabilityMechanic(MechanicFactory mechanicFactory, 
                              ConfigurationSection section) {
        /* We give:
        - an instance of the Factory which created the mechanic
        - the section used to configure the mechanic
        - the item modifier(s)
         */
        super(mechanicFactory, section, item ->
                item.setCustomTag(NAMESPACED_KEY,
                        PersistentDataType.INTEGER, section.getInt("value")));
        this.itemDurability = section.getInt("value");
    }

    public int getItemMaxDurability() {
        return itemDurability;
    }
}

所以现在我们有了一个DurabilityMechanic类,它能够适应任何项目,它将调用我们的DurabilityModifier类来告诉Oraxen在创建它们之前要做哪些修改(这里我们只是在条目中添加一个包含所需新耐久的数据)

第二步:创建属性功能类

和之前一样,使用你的ide功能自动创建一个扩展MechanicFactory的类

class DurabilityMechanicFactory extends MechanicFactory {

    public DurabilityMechanicFactory(ConfigurationSection section) {
        super(section);
    }

    @Override
    public Mechanic parse(ConfigurationSection itemMechanicConfiguration) {
        return null;
    }
}

我们重写解析方法来创建一个新的属性(通过之前创建的DurabilityMechanic类)。我们还想告诉Oraxen这个属性已经成功实现了,可以使用addToImplemented方法加载,所以我们的类现在看起来是这样的

public class DurabilityMechanicFactory extends MechanicFactory {

    public DurabilityMechanicFactory(ConfigurationSection section) {
        super(section);
    }

    @Override
    public Mechanic parse(ConfigurationSection itemMechanicConfiguration) {
        Mechanic mechanic = new DurabilityMechanic(this, itemMechanicConfiguration);
        addToImplemented(mechanic);
        return mechanic;
    }

}

第三步:添加我们的功能(事件)

在我的例子中,我只需要使用一个事件来玩耐久,我会创建一个DurabilityMechanicsManager类来实现Listener,以获得一个干净整洁的代码,但我可以直接在DurabilityMechanicFactory中完成。我告诉Bukkit,当建成后,哪个类管理事件

public class DurabilityMechanicFactory extends MechanicFactory {

    public DurabilityMechanicFactory(ConfigurationSection section) {
        super(section);
        MechanicsManager.registerListeners(OraxenPlugin.get(),
                new DurabilityMechanicsManager(this));
    }

    @Override
    public Mechanic parse(ConfigurationSection itemMechanicConfiguration) {
        Mechanic mechanic = new DurabilityMechanic(this, itemMechanicConfiguration);
        addToImplemented(mechanic);
        return mechanic;
    }

}

为了根据插件管理的真实耐久计算物品上显示的耐久,我使用了一些简单的数学方法:

bukkitDamage等于bukkitMaxDurability减 realMaxDurability除realDurability乘bukkitMaxDurability

所以这就是我的DurabilityMechanicsManager类:

class DurabilityMechanicsManager implements Listener {

    private DurabilityMechanicFactory factory;

    public DurabilityMechanicsManager(DurabilityMechanicFactory factory) {
        this.factory = factory;
    }

    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    private void onItemDamaged(PlayerItemDamageEvent event) {
        ItemStack item = event.getItem();
        String itemID = OraxenItems.getIdByItem(item);
        if (factory.isNotImplementedIn(itemID))
            return;

        DurabilityMechanic durabilityMechanic = 
                (DurabilityMechanic) factory.getMechanic(itemID);

        ItemMeta itemMeta = item.getItemMeta();
        PersistentDataContainer persistentDataContainer = 
                itemMeta.getPersistentDataContainer();
        int realDurabilityLeft = persistentDataContainer
                .get(DurabilityMechanic.NAMESPACED_KEY, PersistentDataType.INTEGER) 
                        - event.getDamage();

        if (realDurabilityLeft > 0) {
            double realMaxDurability = 
                    //because int rounded values suck
                    durabilityMechanic.getItemMaxDurability();
            persistentDataContainer.set(DurabilityMechanic.NAMESPACED_KEY,
                    PersistentDataType.INTEGER, realDurabilityLeft);
            ((Damageable) itemMeta).setDamage((int) (item.getType()
                    .getMaxDurability() - realDurabilityLeft 
                    / realMaxDurability * item.getType().getMaxDurability()));
            item.setItemMeta(itemMeta);
        } else {
            item.setAmount(0);
        }

    }

}

最后一步:注册你的属性

只需在加载插件时调用这一行(例如在你的onEnable方法中)

MechanicsManager.registerMechanicFactory("durability", 
                                DurabilityMechanicFactory.class);

结论

为了正确创建新的属性,建议将其代码分为三部分:

  • 一个扩展MechanicFactory

  • 一个属性,它扩展了属性

  • 在MechanicsManager类中加入您自己的功能(也可以选择)

由于有了ItemModifier,您可以使用您的机制修改项目:

item -> item.setCustomTag(NAMESPACED_KEY,
                        PersistentDataType.INTEGER, section.getInt("value"))

也可以使用类似的方法修改材质包:

ResourcePack.addModifiers(packFolder -> {/* your modifications

最后注册你的技能!

总结一下教程,这里是耐久机制的完整源码

最后更新于