使用鍵(Key)

警告

这些文档是为 SpongeAPI 7 编写的,可能已经过时。 如果你觉得你可以帮助更新它们,请提交一个 PR!

使用数据键访问和修改数据

一个数据访问器提供了通过 Key 访问和修改单个数据的方法。我们从一个示例开始:

代码示例:“治疗”一个数据访问器,如果有可能的话

import org.spongepowered.api.data.DataHolder;
import org.spongepowered.api.data.key.Keys;

public void heal(DataHolder target) {
    if (target.supports(Keys.HEALTH)) {
        double maxHealth = target.get(Keys.MAX_HEALTH).get();
        target.offer(Keys.HEALTH, maxHealth);
    }
}

现在是解释上面这个方法的时候了。

第一行检查这一数据访问器是否支持一个生命值。如果支持,那么就可以被“治疗”。因为一个数据访问器并没有可能在没有最大生命值的情况下拥有关于生命值的数据,反之亦然。使用 supports() 检查数据键是否存在足够了。

第二行使用 get() 方法试图获取数据访问器的最大生命值。除了 get() 方法, getOrNull()getOrElse() 同样通过在第一个参数传入 Key 获取数据。一般情况下应该使用 get() 方法获取一个表示数据的 Optional ,如果数据不存在则返回一个 Optional.empty() 。因为我们已经检查并确认了 Key 的存在,我们就可以直接使用 Optionalget() 方法,而不必进行更进一步的检查。我们也可以直接使用 getOrNull() ,它等价于 get(key).orNull() ,从而摆脱 Optional 。第三种方式是 getOrElse() ,在数据不存在时使用第二个参数提供的默认值代替。

第三行的代码把数据设置回了数据访问器。我们提供一个 Key 表示当前生命值,并提供之前获取到的最大生命值。因此我们就把这个数据访问器“治疗”成了最大生命值。存在一系列的 offer() 方法用于不同的设置需求,所有的 offer() 方法都返回一个 DataTransactionResult ,其包含了数据是否被成功设置。现在,我们将使用那个期望传入一个 Key 和一个对应值的方法,不过在下一页我们会遇到更多。既然我们已经知道了我们对于生命值的设置一定会成功(因为该数据访问器支持这一做法),我们就可以直接无视返回值。

当然,也可以使用 remove() 方法完全移除一个 DataHolder 的数据。只需要简单地把对应的 Key 传入就可以做到这一点。下面的示例演示了如何移除一个数据访问器对应的自定义名称:

public void removeName(DataHolder target) {
    target.remove(Keys.DISPLAY_NAME);
}

轉換資料

除了获取、修改或者设置一个值,还有一种方式可以和数据进行交互。通过使用数据访问器的 transform() 方法,我们可以传入一个 Key 和一个 Function 。在内部,对应数据键的值会被获取并使用给定的 Function 作用于其上。返回值随即被设置回数据访问器,并相应地返回一个 DataTransactionResult

现在,作为示例,我们设置一个数据访问器的最大生命值为原先的两倍。

import java.util.function.Function;

public void buff(DataHolder target) {
    target.transform(Keys.MAX_HEALTH, new Function<Double,Double>() {
        @Override
        public Double apply(Double input) {
            return (input == null) ? 0 : input * 2;
        }
    });
}

当然,因为你在使用 Java 8,所以你可以直接使用 Lambda 表达式减少代码长度:

public void buff(DataHolder target) {
    target.transform(Keys.MAX_HEALTH, d -> (d == null) ? 0 : 2*d);
}

请注意,在两种情况下我们都需要确保我们传入的 Function 可以处理 null 。你还会注意到,这里根本没有检查当前数据访问器是否支持 Keys#MAX_HEALTH 这一数据键。如果当前数据访问器根本不支持这一数据键, transform() 便会执行失败,并返回一个对应的 DataTransactionResult

数据值

有的时候你并不想直接获取数据键对应的实际值,而是被包装起来的数据值。在这种情况下,使用 getValue(key) 方法而不是 get(key) 方法以解决问题。你会获取一个继承了 BaseValue 类的,包含了一份实际值的对象。因为我们知道,当前生命值是以 MutableBoundedValue 的形式存储的,我们可以找到可能的最小生命值,并可以设置其只比这一最小值高一点点。

代码示例:使目标濒临死亡

import org.spongepowered.api.data.value.mutable.MutableBoundedValue;

public void scare(DataHolder target) {
    if (target.supports(Keys.HEALTH)) {
        MutableBoundedValue<Double> health = target.getValue(Keys.HEALTH).get();
        double nearDeath = health.getMinValue() + 1;
        health.set(nearDeath);
        target.offer(health);
    }
}

我们再一次检查目标数据访问器是否支持特定数据键,并获取到了对应的数据值,一个包含有 getMinValue() 方法的 MutableBoundedValue 。因此我们可以获得最小生命值,并加一设置回数据访问器。在内部, set() 这一方法会在设置数据前检查其是否合法并在不合法时悄无声息地返回一个失败结果。执行 health.set(-2) 并不会改变什么因为设置的数据不合法。最后,我们还是需要把这一包装起来的数据值设置回数据访问器。执行 target.offer(health) 和执行 target.offer(health.getKey(), health.get()) 等价。