zh_cn:tutorial:blockentity_modify_data
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| zh_cn:tutorial:blockentity_modify_data [2024/05/30 08:16] – created sjk1949 | zh_cn:tutorial:blockentity_modify_data [2025/06/11 16:02] (current) – [使用数据组件] solidblock | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== 修改方块实体数据 ====== | ====== 修改方块实体数据 ====== | ||
| - | ===== 介绍 ===== | + | 在之前的教程,我们创建了[[blockentity|方块实体]],但是这些方块实体太无聊了,没有任何数据。所以我们尝试给它添加一些数据,并定义了序列化和反序列化数据的方块。 |
| - | 拥有一个与某个 '' | + | ===== 关于 NbtCompound |
| - | 在继续之前,你将需要一个 [[tutorial: | + | 自从 1.21.5 开始,'' |
| + | |||
| + | <code java> | ||
| + | // 没有指定默认值,将返回 Optional | ||
| + | Optional< | ||
| + | |||
| + | // 指定默认值,当对应字段不存在时返回这个默认值 | ||
| + | int value = nbt.getInt(" | ||
| + | </ | ||
| + | |||
| + | 对于集合类型,如复合标签和列表,可以返回一个空的对象作为默认值,例如: | ||
| + | <code java> | ||
| + | // 没有指定默认值,将返回 Optional | ||
| + | Optional< | ||
| + | |||
| + | // 当对应字段不存在时,返回空复合标签 | ||
| + | NbtCompound config = nbt.getCompoundOrEmpty(" | ||
| + | </ | ||
| + | |||
| + | 而在 1.21.5 | ||
| + | <code java> | ||
| + | // 当对应字段不存在时返回 0。 | ||
| + | int value = nbt.getInt(" | ||
| + | |||
| + | // 当对应字段不存在时返回空复合标签。 | ||
| + | NbtCompound config = nbt.getCompound(" | ||
| + | </ | ||
| + | |||
| + | 此外,自从 1.21.5 开始,整个 NBT 复合标签以及里面的字段,可以直接使用 | ||
| + | <code java> | ||
| + | NbtCompound nbt = new NbtCompound(); | ||
| + | nbt.put(" | ||
| + | Optional< | ||
| + | </ | ||
| + | |||
| + | <code java> | ||
| + | NbtCompound nbt = new NbtCompound(); | ||
| + | // 需要使用 RegistryOps,因为物品堆在编码解码时需要访问注册表内容 | ||
| + | nbt.copyFromCodec(ItemStack.MAP_CODEC, | ||
| + | Optional< | ||
| + | </ | ||
| + | |||
| + | 此外,从 1.21.5 开始,列表支持混合不同类型的元素,而在之前的版本中,混入不同类型的元素会导致报错。 | ||
| + | |||
| + | 关于 NBT 变化的更多信息,请参见 | ||
| + | ===== 序列化数据 ===== | ||
| + | |||
| + | 如果想在 '' | ||
| + | |||
| + | '' | ||
| + | |||
| + | 在旧版本中,调用 '' | ||
| + | |||
| + | 知道了这一点,下面的示例演示了如何将 '' | ||
| + | |||
| + | //在 1.21.5 及之前的版本:// | ||
| + | <code java DemoBlockEntity.java> | ||
| + | public class DemoBlockEntity extends BlockEntity { | ||
| + | |||
| + | // 储存数字的当前值 | ||
| + | private int number = 7; | ||
| + | |||
| + | public DemoBlockEntity(BlockPos pos, BlockState state) { | ||
| + | super(TutorialBlockEntityTypes.DEMO_BLOCK, | ||
| + | } | ||
| + | |||
| + | // 序列化方块实体 | ||
| + | @Override | ||
| + | public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { | ||
| + | // 将数字的当前值保存到 nbt | ||
| + | super.writeNbt(nbt, | ||
| + | nbt.putInt(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | //在 1.21.6 及之后的版本:// | ||
| + | <code java> | ||
| + | @Override | ||
| + | public void writeData(WriteView view) { | ||
| + | super.writeData(view); | ||
| + | // 将数字的当前值保存到 nbt | ||
| + | view.putInt(" | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | 为了以后读取数据,您还需要覆盖 '' | ||
| + | |||
| + | //在 1.21.5 及之前的版本:// | ||
| + | <code java> | ||
| + | // 反序列化方块实体 | ||
| + | @Override | ||
| + | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { | ||
| + | super.readNbt(nbt, | ||
| + | |||
| + | number = nbt.getInt(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | //在 1.21.6 及之后的版本:// | ||
| + | <code java> | ||
| + | @Override | ||
| + | public void readData(ReadView view) { | ||
| + | super.readData(ReadView view); | ||
| + | |||
| + | number = view.getInt(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 要获取方块实体的 NBT 数据,调用 '' | ||
| + | |||
| + | 旧有版本中必须调用 '' | ||
| + | |||
| + | ===== 将服务器数据同步至客户端 ===== | ||
| + | 数据通常是在服务器世界读取的。大多数数据都是客户端不需要知道的,例如客户端并不需要知道箱子和熔炉里面有什么,除非打开它。但对于某些方块实体,例如告示牌和旗帜,你需要将所有或者部分数据告知客户端,比如用于渲染。 | ||
| + | |||
| + | 对于 1.17.1 及以下版本,请实现 Fabric API 中的 '' | ||
| + | |||
| + | 对于 1.18 及以上版本,请覆盖 '' | ||
| + | <code java> | ||
| + | @Nullable | ||
| + | @Override | ||
| + | public Packet< | ||
| + | return BlockEntityUpdateS2CPacket.create(this); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registries) { | ||
| + | return createNbt(registries); | ||
| + | } | ||
| + | </ | ||
| <code java> | <code java> | ||
| Line 16: | Line 147: | ||
| } | } | ||
| + | // 以下两个方法,在 1.21.6 中有所改变,参见上面的示例。 | ||
| @Override | @Override | ||
| - | public void writeNbt(NbtCompound nbt) { | + | public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { |
| + | super.writeNbt(nbt, | ||
| nbt.putInt(" | nbt.putInt(" | ||
| - | |||
| - | super.writeNbt(nbt); | ||
| } | } | ||
| | | ||
| @Override | @Override | ||
| - | public void readNbt(NbtCompound nbt) { | + | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { |
| - | super.readNbt(nbt); | + | super.readNbt(nbt, registries); |
| - | number = nbt.getInt(" | + | |
| + | | ||
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | 确保 '' | + | 确保 '' |
| - | ===== From Block' | + | ===== 修改数据 |
| - | 这将会在右键点击方块的位置获得 '' | + | 这将会在右键点击方块的位置获得 '' |
| - | <code java> | + | <code java DemoBlock.class> |
| - | public class DemoBlock extends | + | public class DemoBlock extends |
| [...] | [...] | ||
| @Override | @Override | ||
| - | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | + | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) { |
| if (!world.isClient){ | if (!world.isClient){ | ||
| BlockEntity blockEntity = world.getBlockEntity(pos); | BlockEntity blockEntity = world.getBlockEntity(pos); | ||
| - | if (blockEntity instanceof DemoBlockEntity){ | + | if (blockEntity instanceof DemoBlockEntity |
| - | DemoBlockEntity demoBlockEntity = (DemoBlockEntity) blockEntity; | + | |
| demoBlockEntity.number++; | demoBlockEntity.number++; | ||
| - | player.sendMessage(Text.literal(" | + | player.sendMessage(Text.literal(" |
| - | | + | |
| - | return ActionResult.SUCCESS; | + | |
| } | } | ||
| } | } | ||
| | | ||
| - | return ActionResult.PASS; | + | return ActionResult.SUCCESS; |
| } | } | ||
| } | } | ||
| </ | </ | ||
| + | |||
| + | 每当 '' | ||
| + | |||
| + | 如果起要客户端知识更新(例如,需要用于渲染,或者在没有按 '' | ||
| + | <code java> | ||
| + | world.updateListeners(pos, | ||
| + | </ | ||
| + | |||
| + | ===== 使用数据组件 ===== | ||
| + | |||
| + | 自从 1.20.5 开始,还可以使用数据组件来存储数据,如果要将数据写入到物品堆,则有必要。你还是需要写 '' | ||
| + | |||
| + | 在单独的 '' | ||
| + | |||
| + | <code java TutorialDataComponentTypes.java> | ||
| + | public class TutorialDataComponentTypes { | ||
| + | public static final ComponentType< | ||
| + | .codec(Codec.INT) | ||
| + | .packetCodec(PacketCodecs.INTEGER)); | ||
| + | |||
| + | public static <T> ComponentType< | ||
| + | return Registry.register(Registries.DATA_COMPONENT_TYPE, | ||
| + | } | ||
| + | |||
| + | public static void initialize() { | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 记得有 '' | ||
| + | <code java ExampleMod.java> | ||
| + | public class ExampleMod implements ModInitializer { | ||
| + | [...] | ||
| + | | ||
| + | @Override | ||
| + | public static void onInitialize() { | ||
| + | [..] | ||
| + | TutorialDataComponentTypes.initialize(); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 然后在方块实体中: | ||
| + | |||
| + | <code java DemoBlockEntity.java> | ||
| + | @Override | ||
| + | protected void readComponents(ComponentsAccess components) { | ||
| + | super.readComponents(components); | ||
| + | this.number = components.getOrDefault(ExampleMod.NUMBER, | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected void addComponents(ComponentMap.Builder componentMapBuilder) { | ||
| + | super.addComponents(componentMapBuilder); | ||
| + | componentMapBuilder.add(ExampleMod.NUMBER, | ||
| + | } | ||
| + | |||
| + | // 仅限 1.21.5 及之前的版本: | ||
| + | @Override | ||
| + | public void removeFromCopiedStackNbt(NbtCompound nbt) { | ||
| + | nbt.remove(" | ||
| + | } | ||
| + | | ||
| + | // 对于 1.21.6 及之后的版本: | ||
| + | @Override | ||
| + | public void removeFromCopiedStackData(WriteView view) { | ||
| + | view.remove(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | '' | ||
zh_cn/tutorial/blockentity_modify_data.1717056966.txt.gz · Last modified: 2024/05/30 08:16 by sjk1949