物品的创建

如果你想制作一个自定义的物品,你需要经过若干步骤方能搞定。让我们从最基础的开始,然后制作一把附魔的钻石剑。

创建一个 ItemStack 对象需要 ItemStack 的构造器;这构造器可通过 ItemStack#builder() 方法获得。这个构造器能让我们设定这个物品的类型及耐久。接下来,我们要制作一个带有自定义的名字的无限耐久附魔钻石剑。如果你想要一把普通的钻石剑,没有任何其他奇奇怪怪的数据,只需如此:

import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.api.item.inventory.ItemStack;

public ItemStack generateSword() {
    ItemStack superMegaAwesomeSword = ItemStack.builder()
        .itemType(ItemTypes.DIAMOND_SWORD).build();
    return superMegaAwesomeSword;
}

Creating the basic item is done. Now this is a normal diamond sword that we created, but what if we wanted something more interesting? What about enchanting and naming our sword? We can use Keys#APPLIED_ENCHANTMENTS to give our sword some enchantments. The following example will give our sword every enchantment in the game, to level 1000.

import java.util.List;
import java.util.stream.Collectors;

import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.meta.ItemEnchantment
import org.spongepowered.api.item.Enchantment;

public void withThousandEnchantmentLevel(ItemStack superMegaAwesomeSword){
    List<Enchantment> enchantments = RegistryTypes
        .ENCHANTMENT_TYPE
        .get()
        .stream()
        .filter(type -> type.canBeAppliedToStack(superMegaAwesomeSword))
        .map(type -> Enchantment.of(type, 1000))
        .collect(Collectors.toList());

    superMegaAwesomeSword.offer(Keys.APPLIED_ENCHANTMENTS);
}

现在我们想给这 OP 钻石剑起个看起来很厉害的名字。我们可以直接为 ItemStack 提供一个名字的键值,这样我们就能直接把这个 ItemStack 对象的名字改成 SUPER MEGA AWESOME Diamond Sword (译注:大概就是“狂拽酷炫叼炸天的钻石剑”的意思):

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.item.ItemTypes;

superMegaAwesomeSword.offer(Keys.DISPLAY_NAME, TextComponent.ofChildren(
    Component.text("SUPER ", NamedTextColor.BLUE),
    Component.text("MEGA ", NamedTextColor.GOLD),
    Component.text("AWESOME ", NamedTextColor.DARK_AQUA),
    ItemTypes.DIAMOND_SWORD.get().asComponent().color(NamedTextColor.AQUA));

最后,如果想要让你的剑永不磨损,你可以用另外一个键:

superMegaAwesomeSword.offer(Keys.UNBREAKABLE, true);

完工!现在这把永不损坏的剑不仅有各种附魔,还有一个华丽的名字,拿去给服务器里的小伙伴们玩去吧。

生成物品

当然我们可以直接把这把剑扔进玩家的背包中,但如果我们想让这把剑以掉落物的形式出现呢?是时候让“实体生成”登场了。有鉴于在游戏中,ItemStack 表现出来的外观还是 Item,我们是可以用生成普通 Entity 的方式来搞定这个事情的。此时,EntityType 将会是 EntityTypes#ITEM,同时我们还需要指定 Entity 代表了我们的 ItemStack 实例。这个过程可以通过使用 Keys#REPRESENTED_ITEM 完成。下面是例子:

import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.EntityTypes;
import org.spongepowered.api.event.CauseStackManager.StackFrame;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.server.ServerWorld;

import java.util.Optional;

public void spawnItem(ItemStack superMegaAwesomeSword, ServerLocation spawnLocation) {
    ServerWorld world = spawnLocation.world();
    Item item = world.createEntity(EntityTypes.ITEM, spawnLocation.getPosition());
    item.offer(Keys.REPRESENTED_ITEM, superMegaAwesomeSword.createSnapshot());

    try (StackFrame frame = Sponge.server().causeStackManager().pushCauseFrame()) {
        frame.addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.PLACEMENT);
        word.spawnEntity(item);
    }
}

用方块创建 ItemStack

正常情况下,若需要方块对应的 ItemStack,可以用 ItemStack.Builder#itemType(ItemType) 方法来获得方块对应的物品,但如果我们需要根据 BlockState 来创建 ItemStack 实例呢?只需要使用 ItemStack.Builder#fromBlockState(BlockState) 即可。下面是例子:

import org.spongepowered.api.block.BlockState;

public ItemStack createStack(BlockState state) {
    return ItemStack.builder().fromBlockState(state).build();
}