存取方塊

基本資訊

方塊最常由它的 :javadoc:`Location`來識別與訪問。此位置指向特定座標並包含一個:javadoc:`Extent`。在大多數情況下,一個:javadoc:`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;
}

警告

注意以上的範例並未檢查世界是否存在。若名為worldName的世界不存在,``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(),因為每個方塊只有一個:javadoc:BlockType`實體,但一般仍推薦使用 ``equals()`

方塊資料操作子(Entity Data Manipulators)

和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``只能是真或假。檢查值非常簡單,只要呼叫:javadoc:`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 的兼容性时才有意义。