修改方塊

更改方块类型

更改方块的类型非常简单,只需要调用 Location#setBlockType(BlockType, Cause) 方法,并传入新的 BlockType 参数。例如下面的代码将给定 Location 的方块变成一块海绵:

import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;

public void setToSponge(Location<World> blockLoc, Object myPluginInstance) {
    blockLoc.setBlockType(BlockTypes.SPONGE, Cause.source(myPluginInstance).build());
}

它就是这么简单。如果你只是想要“删除”一个方法(也就是把它替换成空气),你可以只使用 Location#removeBlock(Cause) 这一由 Location 类提供的方法。

更改方块状态

和之前的例子类似,提供了 Location#setBlock(BlockState, Cause) 方法的 Location 类需要传入一个 BlockState 参数。如果想要使用它,你首先必须获取一个 BlockState 用于修改。你可以使用 Location#getBlock() 方法获取一个方块的当前 BlockState ,或者去使用一个 BlockType 的默认状态。下面的例子阐释了后面的使用方法。这一例子先获取了一个海绵方块的默认状态然后进行修改,以产生一个湿海绵方块。

import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.manipulator.mutable.WetData;

public void setToWetSponge(Location<World> blockLoc, Object myPluginInstance) {
    BlockState state = BlockTypes.SPONGE.getDefaultState();
    WetData wetness = Sponge.getDataManager().
        getManipulatorBuilder(WetData.class).get().create();
    wetness.set(wetness.wet().set(true));
    BlockState newState = state.with(wetness.asImmutable()).get();
    blockLoc.setBlock(newState, Cause.source(myPluginInstance).build());
}

因为一个 BlockState 是一个 ImmutableDataHolder ,所以你可以使用它提供的分别名为 with()without() 的方法。这两个方法都会返回一个额外的 BlockState 或者当给定的 ImmutableDataManipulator 不适用于那种 BlockState 代表的方块时,返回一个 Optional.empty()`

with() 方法接受一个 ImmutableDataManipulator 参数,并且会尝试使用给定的数据集合创建一个新的 BlockState 以覆盖已经存在的值。下面的示例把所有泥土方块转变为灰化土。

import org.spongepowered.api.data.key.Keys;
import
    org.spongepowered.api.data.manipulator.immutable.block.ImmutableDirtData;
import org.spongepowered.api.data.manipulator.mutable.block.DirtData;
import org.spongepowered.api.data.type.DirtTypes;

public void dirtToPodzol(Location<World> blockLoc, Object myPluginInstance) {
    BlockState state = blockLoc.getBlock();
    Optional<ImmutableDirtData> dirtDataOpt =
        state.get(ImmutableDirtData.class);

    if (dirtDataOpt.isPresent()) {
        DirtData dirtData = dirtDataOpt.get().asMutable();
        dirtData.set(Keys.DIRT_TYPE, DirtTypes.PODZOL);
        BlockState dirtState = state.with(dirtData.asImmutable()).get();
        blockLoc.setBlock(dirtState, Cause.source(myPluginInstance).build());
    }
}

请注意, DirtData 是一个 BlockState 中数据的一个可变副本。它先进行改变,然后再转换为不可变的,最后产生一个新的 BlockState 替换旧的方块。

without() 方法接受一个类的引用并且会创建一个没有该类所代表的数据的新 BlockState。如果方块状态在该数据不存在的情况下会变得不合法,将使用一个默认值。因此如果泥土方块的 DirtData 被移除了,将会采用默认值 DirtTypes#DIRT 。接下来的示例将会让给定位置的方块变干,如果可能的话。

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

public void dry(Location<World> blockLoc, Object myPluginInstance) {
    BlockState wetState = blockLoc.getBlock();
    Optional<BlockState> dryState = wetState.without(ImmutableWetData.class);
    if (dryState.isPresent()) {
        blockLoc.setBlock(dryState.get(), Cause.source(myPluginInstance).build());
    }
}

既然 WetData 这一 DataManipulator 表示一个布尔值,我们可以通过移除它把方块的湿属性(如果有的话)设置为假。 dryState.isPresent() 检查会在不能变湿的方块类型上失效,因为这时 dryStateOptional.empty()

复制方块

如果你想要复制一个方块的所有数据, BlockSnapshot 可能会是最好的选择。尽管它并不公开所有的数据,但是它存储了一个 BlockType ,它的 BlockState ,和所有额外的 Tile Entity 数据(如果有必要),比如一个箱子的物品栏( Inventory )。 Location 类提供了一个 Location#createSnapshot() 方法以即时创建一个方块的快照( BlockSnapshot )。这使得把方块从一处复制到另一处变得十分简单:

import org.spongepowered.api.block.BlockSnapshot;

public void copyBlock(Location<World> from, Location<World> to, Object myPluginInstance) {
    BlockSnapshot snapshot = from.createSnapshot();
    to.setBlock(snapshot.getState(), Cause.source(myPluginInstance).build());
}