方块的 Tile Entity

Tile entity 是可以执行诸如自动合成一类的附加操作 (熔炉和炼药台),或者提供特殊效果 (例如信标和音符盒) 的方块。它们也保存诸如物品栏或者文字一类的附加数据 (例如箱子、告示牌或命令方块)。

确定 Tile Entity 和它们的类型

我们再一次从 Location 开始。这一名为 Location#getTileEntity() 的方法返回一个方块对应的 Tile Entity。如果对应的方块没有 Tile Entity,它将返回一个 Optional.empty()

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

public boolean isTileEntity(Location<World> blockLoc) {
    return blockLoc.getTileEntity().isPresent();
}

一个 Tile Entity 的类型可以通过 TileEntity#getType() 方法返回的 TileEntityType 获取。它和 BlockType 十分相似。在检查完 Tile Entity 的类型之后我们就可以安全地转换将其为 TileEntity 的相应子类。

import org.spongepowered.api.block.tileentity.Jukebox;
import org.spongepowered.api.block.tileentity.TileEntity;
import org.spongepowered.api.block.tileentity.TileEntityTypes;

public boolean isJukebox(TileEntity entity) {
    return entity.getType().equals(TileEntityTypes.JUKEBOX);
}

public void ejectDiscFromJukebox(TileEntity entity) {
    if (isJukebox(entity)) {
        Jukebox jukebox = (Jukebox) entity;
        jukebox.ejectRecord();
    }
}

在进行一个类型转换之后,各个子接口提供的方法就可以被访问了(在示例中是 Jukebox#ejectRecord() 方法)。关于 TileEntity 的子类及其各自的方法的更多信息可以去 API 中的 org.spongepowered.api.block.tileentity 包( Package )和其子包( Subpackage )中查看。

Tile Entity 数据的访问和修改

和方块状态类似,在 Tile Entity 中存储的数据都可以通过一个 DataManipulator 来访问。既然通过使用 DataManipulator 可以完整地描述数据的类型,所有的数据操作都可以仅使用 TileEntity 接口完成而不需要强制类型转换。

接下来的例子包含了两个修改告示牌的数据的方法。第一个方法 (在可能时) 读取第一行的内容,第二个尝试去设置它并且返回一个布尔值代表操作的成功与否。

import org.spongepowered.api.data.manipulator.mutable.tileentity.SignData;
import org.spongepowered.api.text.Text;

import java.util.Optional;

public Optional<Text> getFirstLine(TileEntity entity) {
    Optional<SignData> data = entity.getOrCreate(SignData.class);
    if (data.isPresent()) {
        return Optional.of(data.get().lines().get(0));
    }
    return Optional.empty();
}

public boolean setFirstLine(TileEntity entity, Text line) {
    if (entity.supports(SignData.class)) {
        SignData sign = entity.getOrCreate(SignData.class).get();
        sign.set(sign.lines().set(0, line));
        entity.offer(sign);
        return true;
    }
    return false;
}

和使用 BlockState 的主要区别,是 Tile Entity 是一个可变的 DataHolder ,而和不可变的 BlockState 不同。

访问物品栏

很大一部分的 Tile Entity 都带有它们自己的物品栏( Inventory ),最值得注意的是箱子和熔炉。物品栏不能直接通过 TileEntity 接口获得,所以有必要执行一个强制类型转换。既然所有包含一个物品栏的 Tile Entity 都继承自 TileEntityCarrier 接口,只需要强制类型转换到它就已经足够了,正如接下来的例子所示。

import org.spongepowered.api.block.tileentity.carrier.TileEntityCarrier;
import org.spongepowered.api.item.inventory.Inventory;

public void useInventory(TileEntity entity) {
    if (entity instanceof TileEntityCarrier) {
        TileEntityCarrier carrier = (TileEntityCarrier) entity;
        Inventory inventory = carrier.getInventory();
        ...
    }
}

请参阅操作物品栏(Inventory)的相关文档。