User Tools

Site Tools


zh_cn:tutorial:inventory

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
zh_cn:tutorial:inventory [2021/09/25 14:37] – [实现Inventory接口] solidblockzh_cn:tutorial:inventory [2024/08/27 03:03] (current) solidblock
Line 1: Line 1:
-====== 将物品放容器中 ====== +====== 在方块存储物品 ====== 
-阅读本教程之前,请确保[[tutorial:blockentity |方块实体]]制作完成。+阅读本教程之前,请确保已经做好了[[zh_cn:tutorial:blockentity|方块实体]]。 
 + 
 +将物品存储在 BlockEntity(方块实体)中的标准方法是使其为 ''Inventory''这使得漏斗(或其他模组)无需任何额外的工作即可从您的 BlockEntity 放入和提取物品。  
 + 
 +这个教程是用于 1.21 的,对于旧版本,一些方法可能改变。 
 + 
 +===== 实现 Inventory 接口 =====
  
-将物品存储在BlockEntity中的标准方法是使其成为''Inventory'' 
-这使得漏斗(或其他mods)无需任何额外的工作即可从您的BlockEntity放入和提取物品。  
-===== 实现Inventory接口 ===== 
 ''Inventory'' 只是一个接口,这意味着实际的 ''ItemStack'' 状态将需要存储在您的''BlockEntity''上。可以使用''DefaultedList <ItemStack>''作为存储这些''ItemStacks''的简便方法,且可以将其默认设置为''ItemStack.Empty'',用来表示物品堆没有任何物品。实现 ''Inventory''非常简单,但乏味且容易出错,因此,我们将使用其默认实现,该实现只需要给它一个''DefaultList <ItemStack>''(将其复制为新文件): ''Inventory'' 只是一个接口,这意味着实际的 ''ItemStack'' 状态将需要存储在您的''BlockEntity''上。可以使用''DefaultedList <ItemStack>''作为存储这些''ItemStacks''的简便方法,且可以将其默认设置为''ItemStack.Empty'',用来表示物品堆没有任何物品。实现 ''Inventory''非常简单,但乏味且容易出错,因此,我们将使用其默认实现,该实现只需要给它一个''DefaultList <ItemStack>''(将其复制为新文件):
 +
 <code java ImplementedInventory.java> <code java ImplementedInventory.java>
 /** /**
- * 一个简单的 {@code Inventory} 实现,仅有默认的方法和物品列表获取器+ * 一个简单的 {@code Inventory} 实现,仅有默认的方法和物品列表的 getter
  *  *
  * Originally by Juuz  * Originally by Juuz
Line 128: Line 132:
 </code> </code>
  
-现在在的 ''BlockEntity'' 中实现''ImplementedInventory'',并为其提供存储该物品的 ''DefaultedList <ItemStack> items'' 实例。对于此例,我们将在物品栏中最多存储2件物品: +现在在的 ''BlockEntity'' 中实现 ''ImplementedInventory'',并为其提供存储该物品的 ''DefaultedList<ItemStack> items'' 实例。对于此例,我们将在物品栏中最多存储 2 件物品: 
-<code java>+<code java DemoBlockEntity.java>
 public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { public class DemoBlockEntity extends BlockEntity implements ImplementedInventory {
     private final DefaultedList<ItemStack> items = DefaultedList.ofSize(2, ItemStack.EMPTY);     private final DefaultedList<ItemStack> items = DefaultedList.ofSize(2, ItemStack.EMPTY);
Line 142: Line 146:
  
 </code> </code>
-我们还需要将物品栏保存到标签并从那里加载。''Inventories'' 具有助方法,可以使得这个非常轻松: +我们还需要将物品栏保存到 NBT 并从那里加载。''Inventories'' 具有助方法,可以使得这个非常轻松: 
-<code java>+<code java DemoBlockEntity.java>
 public class DemoBlockEntity extends BlockEntity implements ImplementedInventory { public class DemoBlockEntity extends BlockEntity implements ImplementedInventory {
     [...]     [...]
     @Override     @Override
-    public void readNbt(NbtCompound nbt) { +    public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
-        super.readNbt(nbt); +        super.readNbt(nbt, registryLookup); 
-        Inventories.readNbt(nbt, items);+        Inventories.readNbt(nbt, items, registryLookup);
     }     }
  
     @Override     @Override
-    public NbtCompound writeNbt(NbtCompound nbt) { +    public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
-        Inventories.writeNbt(nbt, items); +        Inventories.writeNbt(nbt, items, registryLookup); 
-        return super.writeNbt(nbt);+        return super.writeNbt(nbt, registryLookup);
     }     }
 } }
 </code> </code>
 +
 ===== 从物品栏(或任何物品栏)中提取和放入 ===== ===== 从物品栏(或任何物品栏)中提取和放入 =====
-我们覆盖方块类中的 `onUse` 行为以从我们的物品栏中加入和提取物品。注意这也可以对任何 ''Inventory'' 实例完成,不仅是我们自己的(例如,也因此可以对箱子方块做同样的事)。首先我们处理第一个槽位,如果是空的。玩家如果拿着物品,则会将拿着的物品放入。物品进入第一个槽位,如果是空的,或者进入第二个槽位,如果第一个是空的,或者如果第二个是空的,我们则会输出与物品栏有关的信息。注意我们将 ''ItemStack'' 插入物品栏时调用 ''copy()'',这样不会随着玩家的 ''ItemStack'' 而被破坏。 + 
-<code java> +我们覆盖方块类中的 ''onUss'' 行为以从我们的物品栏中加入和提取物品。注意这也可以对任何 ''Inventory'' 实例完成,不仅是我们自己的(例如,也因此可以对箱子方块做同样的事)。 
-public class ExampleBlock extends Block implements BlockEntityProvider {+ 
 +首先我们处理第一个槽位,如果是空的。玩家如果拿着物品,则会将拿着的物品放入。物品进入第一个槽位,如果是空的,或者进入第二个槽位,如果第一个是空的,或者如果第二个是空的,我们则会输出与物品栏有关的信息。 
 + 
 +注意我们将 ''ItemStack'' 插入物品栏时调用 ''copy()'',这样不会随着玩家的 ''ItemStack'' 而被破坏。 
 +<code java DemoBlock.java> 
 +public class DemoBlock extends BlockWithEntity {
     [...]     [...]
     @Override     @Override
-    public boolean activate(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { +    protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { 
-        if (world.isClient) return true+        if (world.isClient) return ActionResult.SUCCESS
-        Inventory blockEntity = (Inventory) world.getBlockEntity(blockPos); +         
 +        if (!(world.getBlockEntity(posinstanceof DemoBlockEntity blockEntity)) { 
 +            return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION
 +        }
  
         if (!player.getStackInHand(hand).isEmpty()) {         if (!player.getStackInHand(hand).isEmpty()) {
-            // 检查第一个槽位是什么,并从玩家手中放入物品 +            // 检查第一个开槽位是什么,并从玩家手中物品放入 
-            if (blockEntity.getInvStack(0).isEmpty()) { +            if (blockEntity.getStack(0).isEmpty()) { 
-                // 将玩家手中的物品堆放入物品栏 +                // 将玩家持有的物品堆放入物品栏 
-                blockEntity.setInvStack(0, player.getStackInHand(hand).copy());+                blockEntity.setStack(0, player.getStackInHand(hand).copy());
                 // 从玩家手中移除物品堆                 // 从玩家手中移除物品堆
                 player.getStackInHand(hand).setCount(0);                 player.getStackInHand(hand).setCount(0);
-            } else if (blockEntity.getInvStack(1).isEmpty()) { +            } else if (blockEntity.getStack(1).isEmpty()) { 
-                blockEntity.setInvStack(1, player.getStackInHand(hand).copy());+                blockEntity.setStack(1, player.getStackInHand(hand).copy());
                 player.getStackInHand(hand).setCount(0);                 player.getStackInHand(hand).setCount(0);
             } else {             } else {
-                // 如果物品栏我们输出其内容 +                // 如果物品栏满,提醒玩家 
-                System.out.println("The first slot holds +                player.sendMessage(Text.literal("物品栏满!第一个槽位是") 
-                        blockEntity.getInvStack(0) and the second slot holds blockEntity.getInvStack(1));+                    .append(blockEntity.getStack(0).getName()) 
 +                    .append(",第二个槽位是"
 +                    .append(blockEntity.getStack(1).getName()));
             }             }
         }          } 
-        return true;+        return ItemActionResult.SUCCESS;
     }     }
 } }
 </code> </code>
  
-玩家不持有物品时,我们将采取相反的行为。我们将从第二个槽位中取出项目然后第二个的第一个为空。如果第一个也是空的,我们将不做任何事情。+玩家不持有物品时,我们将采取相反的行为。我们将从第二个槽位中取出物品如果第二个是空第一个。如果第一个也是空的,不做任何事情。
  
-<code java> +<code java DemoBlock.java> 
-public class ExampleBlock extends Block implements BlockEntityProvider {+public class DemoBlock extends BlockWithEntity {
     [...]     [...]
     @Override     @Override
-    public boolean activate(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) {+    protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
         ...         ...
         if (!player.getStackInHand(hand).isEmpty()) {         if (!player.getStackInHand(hand).isEmpty()) {
             ...             ...
         } else {         } else {
-            // 如果玩家没有持有任何东西,我们依次方块实体中的物品给予玩家+            // 如果玩家手中没有东西,依次给玩家方块实体中的物品
  
-             // 找第一个有物品的槽位,并给玩家 +            // 找第一个有物品的槽位,并给玩家 
-            if (!blockEntity.getInvStack(1).isEmpty()) { +            if (!blockEntity.getStack(1).isEmpty()) { 
-                // 给玩家物品栏中的物品堆 +                // 给玩家物品栏中的物品堆 
-                player.inventory.offerOrDrop(world, blockEntity.getInvStack(1)); +                player.getInventory().offerOrDrop(blockEntity.getStack(1)); 
-                // Remove the stack from the inventory +                // 从物品栏移除物品堆 
-                blockEntity.removeInvStack(1); +                blockEntity.removeStack(1); 
-            } else if (!blockEntity.getInvStack(0).isEmpty()) { +            } else if (!blockEntity.getStack(0).isEmpty()) { 
-                player.inventory.offerOrDrop(world, blockEntity.getInvStack(0)); +                player.getInventory().offerOrDrop(blockEntity.getStack(0)); 
-                blockEntity.removeInvStack(0);+                blockEntity.removeStack(0)
 +            } else { 
 +                return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
             }             }
         }         }
                  
-        return true;+        return ItemActionResult.SUCCESS;
     }     }
 } }
Line 223: Line 239:
 ===== 实现 SidedInventory 接口 ===== ===== 实现 SidedInventory 接口 =====
 如果你希望有基于与方块不同的面(漏斗或者其他模组)进行交互的不同逻辑,你可以实现 SidedInventory 接口。如果说你想使得方块不能从上侧插入,可以这样做: 如果你希望有基于与方块不同的面(漏斗或者其他模组)进行交互的不同逻辑,你可以实现 SidedInventory 接口。如果说你想使得方块不能从上侧插入,可以这样做:
-<code java>+ 
 +<code java DemoBlockEntity.java>
 public class DemoBlockEntity extends BlockEntity implements ImplementedInventory, SidedInventory { public class DemoBlockEntity extends BlockEntity implements ImplementedInventory, SidedInventory {
     [...]     [...]
     @Override     @Override
-    public int[] getInvAvailableSlots(Direction var1) {+    public int[] getInvAvailableSlots(Direction side) {
         // Just return an array of all slots         // Just return an array of all slots
-        int[] result = new int[getItems().size()]; +        return IntStream.of(getItems().size()).toArray();
-        for (int i = 0; i < result.length; i+++
-            result[i] = i; +
-        } +
- +
-        return result;+
     }     }
  
Line 247: Line 259:
     }     }
 } }
- 
 </code> </code>
zh_cn/tutorial/inventory.1632580637.txt.gz · Last modified: 2021/09/25 14:37 by solidblock