zh_cn:tutorial:inventory
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
zh_cn:tutorial:inventory [2019/12/19 05:03] – lightcolour | zh_cn:tutorial:inventory [2023/08/28 10:14] – [从物品栏(或任何物品栏)中提取和放入] wjz_p | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== | + | ====== |
- | Every type of block in Minecraft is represented by a singular | + | 阅读本教程之前,请确保已经做好了[[zh_cn: |
- | This makes it impossible to change a specific block's state by simply changing the '' | + | |
- | as every other block of that type will be affected! | + | 将物品存储在 BlockEntity(方块实体)中的标准方法是使其成为'' |
- | But, what if you //do// want to give a singular block state, so it can change based on some condition? | + | ===== 实现 Inventory 接口 ===== |
- | This is what '' | + | '' |
- | Say we wanted a block to have a hardness of '' | + | < |
- | it would become harder and gain a hardness of '' | + | /** |
- | + | * 一个简单的 {@code Inventory} 实现,仅有默认的方法和物品列表获取器。 | |
- | First we define the boolean property of the block - whether or not it is hard (careful not to import the wrong BooleanProperty!): | + | * |
- | <code java> | + | * Originally by Juuz |
- | public | + | */ |
- | | + | public |
- | } | + | |
- | </code> | + | /** |
- | Then we need to register the property by overriding '' | + | * 从此物品栏中检索物品。 |
- | <code java> | + | * 每次被调用时必须返回相同实例。 |
- | public class MyBlock extends Block { | + | */ |
- | [...] | + | DefaultedList< |
+ | |||
+ | /** | ||
+ | * 从物品列表创建物品栏。 | ||
+ | */ | ||
+ | static | ||
+ | return () -> items; | ||
+ | } | ||
+ | |||
+ | | ||
+ | * 根据指定的尺寸创建新的物品栏。 | ||
+ | */ | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * 返回物品栏的大小。 | ||
+ | */ | ||
@Override | @Override | ||
- | | + | |
- | | + | |
} | } | ||
| | ||
+ | /** | ||
+ | * 检查物品栏是否为空。 | ||
+ | * @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; | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | Then we need to set the default state of our property in the block constructor: | + | |
+ | 现在在您的 '' | ||
<code java> | <code java> | ||
- | public class MyBlock | + | public class DemoBlockEntity |
- | | + | |
- | public | + | |
- | | + | @Override |
- | setDefaultState(getStateManager().getDefaultState().with(HARDENED, | + | public |
+ | | ||
} | } | ||
- | | + | |
} | } | ||
- | </ | ||
- | (To set multiple properties, chain '' | ||
- | Now, to set the property we need to call '' | + | </ |
- | + | 我们还需要将物品栏保存到标签并从那里加载。'' | |
- | (Replace ''MyBlocks.MY_BLOCK_INSTANCE'' | + | |
<code java> | <code java> | ||
- | public class MyBlock | + | public class DemoBlockEntity |
[...] | [...] | ||
@Override | @Override | ||
- | public | + | public |
- | | + | |
- | return | + | Inventories.readNbt(nbt, items); |
+ | } | ||
+ | |||
+ | @Override | ||
+ | public NbtCompound writeNbt(NbtCompound nbt) { | ||
+ | Inventories.writeNbt(nbt, items); | ||
+ | return | ||
} | } | ||
} | } | ||
</ | </ | ||
- | And to use the property we call '' | + | ===== 从物品栏(或任何物品栏)中提取和放入 ===== |
+ | 我们覆盖方块类中的 `onUse` 行为以从我们的物品栏中加入和提取物品。注意这也可以对任何 | ||
<code java> | <code java> | ||
- | public class MyBlock | + | public class ExampleBlock |
[...] | [...] | ||
@Override | @Override | ||
- | public | + | public |
- | | + | |
- | if(hardened) return 2.0f; | + | Inventory blockEntity |
- | else return | + | |
+ | |||
+ | if (!player.getStackInHand(hand).isEmpty()) { | ||
+ | // Check what is the first open slot and put an item from the player' | ||
+ | if (blockEntity.getStack(0).isEmpty()) { | ||
+ | // Put the stack the player is holding into the inventory | ||
+ | blockEntity.setStack(0, | ||
+ | // Remove the stack from the player' | ||
+ | player.getStackInHand(hand).setCount(0); | ||
+ | } else if (blockEntity.getStack(1).isEmpty()) { | ||
+ | blockEntity.setStack(1, | ||
+ | player.getStackInHand(hand).setCount(0); | ||
+ | } else { | ||
+ | // If the inventory is full we'll print it's contents | ||
+ | System.out.println(" | ||
+ | + blockEntity.getStack(0) + " and the second slot holds " + blockEntity.getStack(1)); | ||
+ | } | ||
+ | } | ||
+ | return ActionResult.SUCCESS; | ||
} | } | ||
} | } | ||
</ | </ | ||
- | ==== Adding models for your blockstates ==== | + | 当玩家不持有物品时,我们将采取相反的行为。我们将从第二个槽位中取出项目,然后第二个中的第一个为空。如果第一个也是空的,我们将不做任何事情。 |
- | You can also make the texture and model of your block change based on the state. This is done through a JSON file called a Blockstate JSON. All blocks need a blockstate JSON, whether they have multiple states or not, but the contents of the JSON can be as simple or complex as you like. If you want to change the textures of your block based on the state, you //will// need multiple models. | + | <code java> |
+ | public class ExampleBlock extends Block implements BlockEntityProvider { | ||
+ | [...] | ||
+ | @Override | ||
+ | public boolean activate(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { | ||
+ | ... | ||
+ | if (!player.getStackInHand(hand).isEmpty()) { | ||
+ | ... | ||
+ | } else { | ||
+ | | ||
- | Let's say you register an instance of '' | + | // 查找第一个有物品的槽位,并给予玩家 |
- | + | if (!blockEntity.getInvStack(1).isEmpty()) { | |
- | <code JavaScript resources/assets/mymod/ | + | |
- | { | + | player.inventory.offerOrDrop(world, blockEntity.getInvStack(1)); |
- | " | + | // Remove the stack from the inventory |
- | | + | blockEntity.removeInvStack(1); |
+ | } else if (!blockEntity.getInvStack(0).isEmpty()) | ||
+ | | ||
+ | blockEntity.removeInvStack(0); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return true; | ||
} | } | ||
} | } | ||
</ | </ | ||
- | Let's break this simple example down. There are a couple important parts to this JSON: | + | ===== 实现 SidedInventory 接口 ===== |
+ | 如果你希望有基于与方块不同的面(漏斗或者其他模组)进行交互的不同逻辑,你可以实现 SidedInventory 接口。如果说你想使得方块不能从上侧插入,可以这样做: | ||
+ | <code java> | ||
+ | public class DemoBlockEntity extends BlockEntity implements ImplementedInventory, | ||
+ | [...] | ||
+ | @Override | ||
+ | public int[] getInvAvailableSlots(Direction var1) { | ||
+ | // Just return an array of all slots | ||
+ | int[] result = new int[getItems().size()]; | ||
+ | for (int i = 0; i < result.length; | ||
+ | result[i] = i; | ||
+ | } | ||
- | - The ''" | + | return result; |
- | - A variant named ''""'' | + | } |
- | - The object assigned to the ''""'' | + | |
- | - The ''" | + | |
- | If you //do// want to have different models for each blockstate, you'd want to add multiple variants. For the same '' | + | @Override |
+ | public boolean canInsert(int slot, ItemStack stack, Direction direction) { | ||
+ | return direction != Direction.UP; | ||
+ | } | ||
- | <code JavaScript resources/ | + | @Override |
- | { | + | |
- | | + | |
- | | + | |
- | " | + | |
} | } | ||
} | } | ||
+ | |||
</ | </ | ||
- | |||
- | In this JSON, there are two variants, one for each possibility of the '' | ||
- | |||
- | Variants are based on possible permutations of the properties added to your block. A property can be totally ignored in the blockstate JSON if you want, like in the first blockstate JSON where we ignored the '' | ||
- | |||
- | This is only a simple introduction to blockstate JSONs. All of the tricks you can do with blockstate and model JSONs are documented on the [[https:// | ||
- | ==== A note about performance ==== | ||
- | Every possible state of a block is registered at the start of the game. This means that if you have 14 boolean properties, the block has 2^14 = 16384 different states and 2^14 states are registered. For this reason blocks should not contain too many blockstate properties. Rather, blockstates should be mostly reserved for visuals, and [[tutorial: |
zh_cn/tutorial/inventory.txt · Last modified: 2023/08/28 10:14 by wjz_p