# 创建你属于自己的属性

## 技能是如何运转的?

### 属性是什么?

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

{% hint style="info" %}
耐久机制的工作原理是将物品的耐久存储在它的metadatas中，并使用耐久度条来显示它的自定义耐久度，而不是它的真正耐久度
{% endhint %}

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

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

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

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

{% hint style="info" %}
在本教程中，我将以耐久机制为例（因为它非常简单易懂），但你可以按照本教程来创建你想要的机制
{% endhint %}

### 第一步：创建我们的属性类

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

```java
class DurabilityMechanic extends Mechanic {

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

}
```

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

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

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

#### 属性配置部分的外观：

```java
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的类

```java
class DurabilityMechanicFactory extends MechanicFactory {

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

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

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

```java
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，当建成后，哪个类管理事件

```java
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&#x20;

所以这就是我的DurabilityMechanicsManager类:

```java
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方法中）

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

## 结论

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

* 一个扩展MechanicFactory
* 一个属性，它扩展了属性
* 在MechanicsManager类中加入您自己的功能（也可以选择）

{% hint style="info" %}
由于有了ItemModifier，您可以使用您的机制修改项目：

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

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

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

{% endhint %}

最后注册你的技能！

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://3504743864.gitbook.io/oraxen-wiki/kai-fa/chuang-jian-ni-shu-yu-zi-ji-de-shu-xing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
