访问方块

基本信息

方块一般可以通过他们的 Location (位置) 来识别和访问。这个位置指向到一个 Extent (地域) 的特定坐标中。在大多数情况下,一个 World (世界) 会被用作地域。

import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

public Location<World> getBlockAt(String worldName, int posX, int posY, int posZ) {
    World world = Sponge.getServer().getWorld(worldName).get();
    Location<World> blockLoc = new Location<World>(world, posX, posY, posZ);
    return blockLoc;
}

警告

请注意上面的示例不会检查世界的存在与否。getWorld(worldName).get() 会在同名世界没有加载的情况下失败。

通过这个 Location 对象你可以进一步获取关于方块的信息。下面的代码通过检查方块类型来确认一个方块引用是否是任何种类的旗帜。

import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.BlockTypes;

public boolean isBanner(Location<World> blockLoc) {
    BlockType type = blockLoc.getBlock().getType();
    return type.equals(BlockTypes.STANDING_BANNER)
            || type.equals(BlockTypes.WALL_BANNER);
}

小技巧

运算符``==``可以代替``equals()``方法,因为对于每个方块,它们分别只有一个 BlockType 实例,尽管我们仍然建议使用``equals()``。

操作方块数据

和API的其他部分的存储方式类似,一个方块的数据被以 DataManipulator 的方式存储。它是一个存储了方块的各种角度的信息的容器。这样的信息有方块的方向、特殊类型(例如石头和花岗岩)等。获取这样的数据是十分简单的,如果想要获取方块的方向,你只需要使用 DirectionalData

import org.spongepowered.api.data.key.Keys;
import org.spongepowered.api.data.manipulator.mutable.block.DirectionalData;

public boolean isFacingNorth(Location<World> blockLoc) {
    Optional<DirectionalData> optionalData = blockLoc.get(DirectionalData.class);
    if (!optionalData.isPresent()) {
        return false;
    }
    DirectionalData data = optionalData.get();
    if (data.get(Keys.DIRECTION).get().equals(Direction.NORTH)) {
        return true;
    }
    return false;
}

首先,我们需要知道我们需要的``DataManipulator``的子接口是什么样子。我们可以在 org.spongepowered.api.data.manipulator.mutableorg.spongepowered.api.data.manipulator.mutable.block 两个包下找到适用于方块的部分。然后,我们直接把对应的class传入 Location 类的 get(DataManipulator) 方法从而返回一个 Optional 。然后我们就需要通过 isPresent() (译者注:原文为 ifPresent() ,怀疑其笔误)方法判断这一 DataManipulator 是否真的存在,如果存在,我们就可以使用它了。

更多和 DataManipulator 有关的东西可以在 数据 API 文档 中找到。

小技巧

如果一个方块永远支持一种特定的``DataManipulator``,比如台阶支持``DirectionalData``,自然就没有必要检查``isPresent()``。直接通过添加``.get()``在语句的末尾就可以获取被Optional包装的数据。请注意,如果一个方块不支持这种特定的``DataManipulator``,那么这样的操作会产生一个``NullPointerException``。

方块状态

一个 BlockState 包含一个 BlockType、所有应用于该方块的 DataManipulator 和属性、以及该方块所拥有的 BlockTrait。它储存了一个特定的方块的所有不可变数据。一种用法是获取一个 ImmutableDataManipulator ,就像下面这样:

import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.manipulator.immutable.ImmutableWetData;

public void isWet(Location blockLoc) {
    BlockState sponge = blockLoc.getBlock();
    if (!sponge.getType().equals(BlockTypes.SPONGE)) {
        return false;
    }
    Optional<ImmutableWetData> wetness = sponge.get(ImmutableWetData.class);
    return wetness.isPresent();
}

更多和可变或不可变的 DataManipulator 有关的东西可以在 数据 API 文档 中找到。

方块属性

一个方块可以包含若干种属性。一种属性是一类定义了特定方块的游戏逻辑的值的集合。例如,方块可以包含既定的爆炸抗性值,这一值可以被拿来使用而不需要逐个检查每个方块的种类。比如如果我们想要获取爆炸抗性并检查它是否大于等于一,我们就可以这么做:

import org.spongepowered.api.data.property.DoubleProperty;
import org.spongepowered.api.data.property.block.BlastResistanceProperty;

public boolean blastResistanceGreaterThanOne(Location<World> blockLoc) {
    Optional<BlastResistanceProperty> optional =
        blockLoc.getProperty(BlastResistanceProperty.class);

    if(optional.isPresent()) {
        BlastResistanceProperty resistance = optional.get();
        DoubleProperty one = DoubleProperty.greaterThanOrEqual(1);
        return one.matches(resistance);
    }
    return false;
}

这就可以得到我们针对的方块的爆炸抗性值并和一个新 DoubleProperty 进行比较,因为 BlastResistanceProperty 是``DoubleProperty``的子类。这一方法就会返回爆炸抗性是否大于等于一,也就是被放置在``matches()``方法里的``DoubleProperty``。如果我们想要知道它是否比二小,我们就会把相应的方法替换成``lessThan()``。

如果我们在比较两个已经存在的属性,那么先会判断第一个的 Operator ,这里也就是我们设置的 DoublePropertyOperator 。如果它是 DELEGATE ,也就是并不存在,那么它就会获取第二个的 Operator ,也就是 matches() 中的属性的 Operator 。如果两个属性的 Operator 都是 DELEGATE ,那么它将会返回假。下面是比较两个 PoweredProperty 和一个 BooleanProperty 的例子:

import org.spongepowered.api.data.property.block.PoweredProperty;

public boolean areBlocksPowered(Location<World> blockLoc, Location<World> blockLoc2) {
    Optional<PoweredProperty> optional = blockLoc.getProperty(PoweredProperty.class);
    Optional<PoweredProperty> optional2 = blockLoc2.getProperty(PoweredProperty.class);

    if(optional.isPresent() && optional2.isPresent()) {
        PoweredProperty property1 = optional2.get();
        PoweredProperty property2 = optional2.get();
        BooleanProperty booleanProperty = BooleanProperty.of(property1);
        BooleanProperty booleanProperty2 = BooleanProperty.of(true);

        if(booleanProperty2.matches(property1)) {
            return booleanProperty.matches(property2);
        }
    }
    return false;
}

第二个``if``条件判断其中一个属性是否为真。如果其为真而且两个属性一致,那么两个属性自然都为真。因此,我们不需要检查第二个值就可以知道两个方块都是被充能的。

可能的方块属性列表可以在 org.spongepowered.api.data.property.block 下找到。

方块特性

方块特性是一个方块的当前状态的确定值。一个方块可能或不可能包含方块特性取决于方块的种类。例如:方块“床”有一个名为``BED_OCCUPIED``的方块特性, BooleanTrait 。作为一个布尔值它只有真或假两种可能值,所以方块特性``BED_OCCUPIED``也只可能为真或假。检查这一特性值十分简单,只需要调用 BlockState#getTraitValue(BlockTrait) 方法就可以了。一种针对床的例子如下:

import org.spongepowered.api.block.trait.BooleanTraits;

public boolean isBedOccupied(Location<World> blockLoc) {
    if(blockLoc.getBlock().getType().equals(BlockTypes.BED)) {
        return blockLoc.getBlock().getTraitValue(BooleanTraits.BED_OCCUPIED).get();
    }
    return false;
}

警告

如果有可能,请尽量使用 DataManipulator 以替代 BlockTrait ,因为 BlockTrait 只是在考虑与 Mod 的兼容性时才有意义。