创建有方块实体的方块时,可能需要旗下有来自你的 BlockItem
的 ItemStack
的预先定义的 NBT 数据,或者在破坏方块后存在 BlockEntity
数据至 ItemStack
。
要让方块掉落的物品堆中能够有来自方块实体的 NBT 或数据组件,只需要改变战利品表。
因为引入了数据组件,你需要在方块实体中,存在方块物品的数据组件。这需要你将 NBT 数据存储为数据组件。更多请参见使用数据组件。
如果在使用 1.21 之后的版本,请将路径中的单词 loot_table
替换为 loot_tables
。
{ "pools": [ { "rolls": 1.0, "bonus_rolls": 0.0, "entries": [ { "name": "tutorial:demo_block", "type": "minecraft:item" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] } ], "functions": [ { "source": "block_entity", "include": [ "tutorial:number" ], "function": "minecraft:copy_components" } ] }
其中
"include"
:数据组件类型的 ID。在 1.20.5 之前,数据组件没有被引入,所以只要复制 NBT。
{ "type": "minecraft:block", "pools": [ { "rolls": 1.0, "entries": [ { "type": "minecraft:item", "name": "tutorial:demo_block", "functions": [ { "function": "minecraft:copy_nbt", "source": "block_entity", "ops": [ { "source": "number", "target": "BlockEntityTag.number", "op": "replace" } ] } ] } ] } ] }
其中:
"source"
是 NBT 的键,我们在 DemoBlockEntity
类的 writeNbt
和 readNbt
方块中有使用过 – "number"
"target"
是掉落的ItemStack
的 NBT 的路径(source
前面是 "BlockEntityTag"
键,需要这个才能放置有存储的数据的方块) – "BlockEntityTag.number"
要保存更多的字段,只需要往 ops
字段添加更多的 replace 操作(有source、target 和 op)。
对于 1.20.5 以及之后的版本,要获取存储在物品堆中的方块实体数据,可以使用其数据组件。
对于 1.20.5 及之后的版本:
public class DemoBlock extends BlockWithEntity { [...] @Override public void appendTooltip(ItemStack stack, Item.TooltipContext context, List<Text> tooltip, TooltipType options) { final Integer i = stack.get(TutorialDataComponentTypes.NUMBER); if (i == null) return; tooltip.add(Text.literal("数字:" + i)); } }
对于 1.20.5 之前的版本,我们调用 getBlockEntityNbt
,这会在内部调用 getSubNbt
。
对于 1.20.5 之前的版本:
public class DemoBlock extends BlockWithEntity { [...] @Override public void appendTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext context) { NbtCompound nbt = BlockItem.getBlockEntityNbt(stack); if (nbt == null) return; tooltip.add(Text.literal("数字: " + nbt.getInt("number")) } }
类似地,可以使用 getName
方法,这样数据可以直接显示在名称中,在这个例子中,你需要修改方块物品注册的方块以创建 DemoBlockItem
而不是 BlockItem
。
public class DemoBlockItem extends BlockItem { public DemoBlockItem(Block block, Settings settings) { super(block, settings); } @Override public Text getName(ItemStack stack) { final MutableText name = Text.translatable(stack.getTranslationKey()); if (stack.contains(TutorialDataComponentTypes.NUMBER)) { name.append(" - number=" + stack.get(TutorialDataComponentTypes.NUMBER)); } return name; } }
在创造模式下,当你按下 Ctrl
的同时拾取物品(按下鼠标中键),会得到带有所有方块实体数据的物品堆。但是,如果不按下 Ctrl
,只会得到没有数据的,除非在 DemoBlock
类中修改 getPickStack
方法:
@Override public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) { final ItemStack pickStack = super.getPickStack(world, pos, state); final BlockEntity blockEntity = world.getBlockEntity(pos); if (blockEntity instanceof DemoBlockEntity demoBlockEntity) { pickStack.applyComponentsFrom(demoBlockEntity.createComponentMap()); } return pickStack; }
注意:没有按下Ctrl
时,拾取方块是仅发生在客户端的,所以你应该修改toUpdatePacket
和toInitialChunkDataNbt
并在修改数据时调用updateListeners
(参见将服务器数据同步至客户端)。
原版全码可以看到更多例子,例如 ShulkerBoxBlock
和 ShulkerBoxBlockEntity
,实现了 Nameable
接口,并有通过 ItemStack
和 BlockEntity
存储自定义名字的代码。也有一些其他有用的信息: