zh_cn:tutorial:inventory
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
zh_cn:tutorial:inventory [2019/12/19 05:03] – lightcolour | zh_cn:tutorial:inventory [2023/08/28 10:14] (current) – [从物品栏(或任何物品栏)中提取和放入] 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 | + | <code java> |
- | + | public class ExampleBlock extends Block implements BlockEntityProvider { | |
- | Let's say you register | + | [...] |
- | + | @Override | |
- | <code JavaScript resources/ | + | public ActionResult onUse(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { |
- | { | + | |
- | " | + | if (!player.getStackInHand(hand).isEmpty()) { |
- | | + | ... |
+ | } else { | ||
+ | // If the player is not holding anything we'll get give him the items in the block entity one by one | ||
+ | |||
+ | // Find the first slot that has an item and give it to the player | ||
+ | if (!blockEntity.getStack(1).isEmpty()) { | ||
+ | | ||
+ | player.getInventory().offerOrDrop(blockEntity.getStack(1)); | ||
+ | | ||
+ | blockEntity.removeStack(1); | ||
+ | } else if (!blockEntity.getStack(0).isEmpty()) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return ActionResult.SUCCESS; | ||
} | } | ||
} | } | ||
</ | </ | ||
- | 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.1576731825.txt.gz · Last modified: 2019/12/19 05:03 by lightcolour