zh_cn:tutorial:inventory
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| zh_cn:tutorial:inventory [2019/12/19 05:03] – created lightcolour | zh_cn:tutorial:inventory [2024/08/27 03:03] (current) – solidblock | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== | + | ====== |
| + | 阅读本教程之前,请确保已经做好了[[zh_cn: | ||
| - | ===== Introduction ===== | + | 将物品存储在 BlockEntity(方块实体)中的标准方法是使其成为 '' |
| - | A BlockEntity is primarily used to store data within blocks. Before creating one, you will need a [[tutorial: | + | 这个教程是用于 1.21 的,对于旧版本,一些方法可能改变。 |
| - | ===== Creating a BlockEntity | + | ===== 实现 Inventory 接口 |
| - | The simplest Block Entity simply extends | + | '' |
| - | <code java> | + | < |
| - | public | + | /** |
| - | public DemoBlockEntity() { | + | * 一个简单的 {@code Inventory} 实现,仅有默认的方法和物品列表的 getter。 |
| - | super(ExampleMod.DEMO_BLOCK_ENTITY); | + | * |
| - | | + | * Originally by Juuz |
| + | */ | ||
| + | public | ||
| + | |||
| + | /** | ||
| + | * 从此物品栏中检索物品。 | ||
| + | * 每次被调用时必须返回相同实例。 | ||
| + | */ | ||
| + | DefaultedList< | ||
| + | |||
| + | /** | ||
| + | * 从物品列表创建物品栏。 | ||
| + | */ | ||
| + | static ImplementedInventory of(DefaultedList< | ||
| + | | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 根据指定的尺寸创建新的物品栏。 | ||
| + | */ | ||
| + | static ImplementedInventory ofSize(int size) { | ||
| + | return of(DefaultedList.ofSize(size, | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 返回物品栏的大小。 | ||
| + | */ | ||
| + | @Override | ||
| + | default int size() { | ||
| + | return getItems().size(); | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 检查物品栏是否为空。 | ||
| + | * @return true,如果物品栏仅有一个空堆,否则为true。 | ||
| + | */ | ||
| + | @Override | ||
| + | default boolean isEmpty() { | ||
| + | for (int i = 0; i < size(); i++) { | ||
| + | ItemStack stack = getStack(i); | ||
| + | if (!stack.isEmpty()) { | ||
| + | return false; | ||
| + | } | ||
| + | } | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 检索槽位中的物品。 | ||
| + | */ | ||
| + | @Override | ||
| + | default ItemStack getStack(int slot) { | ||
| + | return getItems().get(slot); | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 从物品栏槽位移除物品。 | ||
| + | * @param slot 从该槽位移除。 | ||
| + | * @param count 需要移除的物品个数。如果槽位中的物品少于需要的,则将其全部取出。 | ||
| + | */ | ||
| + | @Override | ||
| + | default ItemStack removeStack(int slot, int count) { | ||
| + | ItemStack result = Inventories.splitStack(getItems(), | ||
| + | if (!result.isEmpty()) { | ||
| + | markDirty(); | ||
| + | } | ||
| + | return result; | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 从物品栏槽位移除所有物品。 | ||
| + | * @param slot 从该槽位移除。 | ||
| + | */ | ||
| + | @Override | ||
| + | default ItemStack removeStack(int slot) { | ||
| + | return Inventories.removeStack(getItems(), | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 将物品栏槽位中的当前物品堆替换为提供的物品堆。 | ||
| + | * @param slot 替换该槽位的物品堆。 | ||
| + | * @param stack 替换后新的物品堆。如果堆对于此物品栏过大({@link Inventory# | ||
| + | */ | ||
| + | @Override | ||
| + | default void setStack(int slot, ItemStack stack) { | ||
| + | getItems().set(slot, | ||
| + | if (stack.getCount() > getMaxCountPerStack()) { | ||
| + | stack.setCount(getMaxCountPerStack()); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 清除物品栏。 | ||
| + | */ | ||
| + | @Override | ||
| + | default void clear() { | ||
| + | getItems().clear(); | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * 将方块状态标记为脏。 | ||
| + | * 更改物品栏之后必须调用,所以游戏正确地储存物品栏内容并提取邻近方块物品栏改变。 | ||
| + | */ | ||
| + | @Override | ||
| + | default void markDirty() { | ||
| + | // 需要行为时,覆盖此方法。 | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * @return true 如果玩家可以使用物品栏,否则为 false。i | ||
| + | */ | ||
| + | @Override | ||
| + | default boolean canPlayerUse(PlayerEntity player) { | ||
| + | return true; | ||
| + | } | ||
| } | } | ||
| </ | </ | ||
| - | Bellow will show you how to create the '' | + | 现在在你的 |
| + | <code java DemoBlockEntity.java> | ||
| + | public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { | ||
| + | private final DefaultedList< | ||
| - | You can simply add variables to this barebone class or implement interfaces such as '' | + | @Override |
| + | public DefaultedList< | ||
| + | return items; | ||
| + | } | ||
| + | [...] | ||
| - | ===== Registring your BlockEntity ===== | ||
| - | |||
| - | Once you have created the '' | ||
| - | |||
| - | The '' | ||
| - | |||
| - | <code java> | ||
| - | public static BlockEntityType< | ||
| - | |||
| - | @Override | ||
| - | public void onInitialize() { | ||
| - | | ||
| } | } | ||
| + | |||
| </ | </ | ||
| + | 我们还需要将物品栏保存到 NBT 并从那里加载。'' | ||
| + | <code java DemoBlockEntity.java> | ||
| + | public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { | ||
| + | [...] | ||
| + | @Override | ||
| + | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { | ||
| + | super.readNbt(nbt, | ||
| + | Inventories.readNbt(nbt, | ||
| + | } | ||
| - | Once your '' | + | |
| - | + | public | |
| - | <code java> | + | |
| - | @Override | + | |
| - | public | + | } |
| - | | + | |
| } | } | ||
| </ | </ | ||
| - | ===== Serializing Data ===== | + | ===== 从物品栏(或任何物品栏)中提取和放入 |
| - | If you want to store any data in your '' | + | 我们覆盖方块类中的 |
| - | '' | + | 首先我们处理第一个槽位,如果是空的。玩家如果拿着物品,则会将拿着的物品放入。物品进入第一个槽位,如果是空的,或者进入第二个槽位,如果第一个是空的,或者如果第二个是空的,我们则会输出与物品栏有关的信息。 |
| - | <code java> | + | 注意我们将 '' |
| - | public class DemoBlockEntity | + | < |
| + | public class DemoBlock | ||
| + | [...] | ||
| + | @Override | ||
| + | protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | ||
| + | if (world.isClient) return ActionResult.SUCCESS; | ||
| + | |||
| + | if (!(world.getBlockEntity(pos) instanceof DemoBlockEntity blockEntity)) { | ||
| + | return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; | ||
| + | } | ||
| - | // Store the current value of the number | + | if (!player.getStackInHand(hand).isEmpty()) { |
| - | | + | |
| - | + | | |
| - | | + | // 将玩家持有的物品堆放入物品栏 |
| - | super(ExampleMod.DEMO_BLOCK_ENTITY); | + | blockEntity.setStack(0, player.getStackInHand(hand).copy()); |
| - | } | + | // 从玩家手中移除物品堆 |
| - | + | | |
| - | // Serialize the BlockEntity | + | } else if (blockEntity.getStack(1).isEmpty()) { |
| - | public CompoundTag toTag(CompoundTag tag) { | + | |
| - | super.toTag(tag); | + | |
| - | + | } else { | |
| - | // Save the current value of the number to the tag | + | // 如果物品栏满,提醒玩家 |
| - | tag.putInt("number", number); | + | |
| - | + | .append(blockEntity.getStack(0).getName()) | |
| - | return | + | .append(" |
| - | | + | .append(blockEntity.getStack(1).getName())); |
| + | } | ||
| + | } | ||
| + | | ||
| + | } | ||
| } | } | ||
| </ | </ | ||
| - | In order to retrieve the data later, you will also need to override '' | + | 玩家不持有物品时,我们将采取相反的行为。我们将从第二个槽位中取出物品,如果第二个是空的就第一个。如果第一个也是空的,就不做任何事情。 |
| - | <code java> | + | < |
| - | // Deserialize the BlockEntity | + | public class DemoBlock extends BlockWithEntity { |
| - | public void fromTag(CompoundTag tag) { | + | [...] |
| - | super.fromTag(tag); | + | @Override |
| - | number = tag.getInt(" | + | protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { |
| + | ... | ||
| + | if (!player.getStackInHand(hand).isEmpty()) { | ||
| + | ... | ||
| + | } else { | ||
| + | | ||
| + | |||
| + | // 找到第一个有物品的槽位,并给玩家 | ||
| + | if (!blockEntity.getStack(1).isEmpty()) { | ||
| + | // 给玩家物品栏中的物品堆 | ||
| + | player.getInventory().offerOrDrop(blockEntity.getStack(1)); | ||
| + | // 从物品栏移除物品堆 | ||
| + | blockEntity.removeStack(1); | ||
| + | } else if (!blockEntity.getStack(0).isEmpty()) { | ||
| + | player.getInventory().offerOrDrop(blockEntity.getStack(0)); | ||
| + | blockEntity.removeStack(0); | ||
| + | } else { | ||
| + | return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | return ItemActionResult.SUCCESS; | ||
| + | } | ||
| } | } | ||
| </ | </ | ||
| - | Once you have implemented the '' | + | ===== 实现 SidedInventory 接口 ===== |
| + | 如果你希望有基于与方块不同的面(漏斗或者其他模组)进行交互的不同逻辑,你可以实现 SidedInventory 接口。如果说你想使得方块不能从上侧插入,可以这样做: | ||
| - | If you need to sync some of your '' | + | <code java DemoBlockEntity.java> |
| + | public | ||
| + | [...] | ||
| + | @Override | ||
| + | public int[] getInvAvailableSlots(Direction side) { | ||
| + | // Just return an array of all slots | ||
| + | return IntStream.of(getItems().size()).toArray(); | ||
| + | } | ||
| - | ===== Overview ===== | + | @Override |
| + | public boolean canInsert(int slot, ItemStack stack, Direction direction) { | ||
| + | return direction != Direction.UP; | ||
| + | } | ||
| - | You should now have your very own '' | + | @Override |
| + | public boolean canExtract(int slot, ItemStack stack, Direction direction) { | ||
| + | return true; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
zh_cn/tutorial/inventory.1576731787.txt.gz · Last modified: 2019/12/19 05:03 by lightcolour