tutorial:blockentity_modify_data
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorial:blockentity_modify_data [2024/08/26 00:31] – solidblock | tutorial:blockentity_modify_data [2025/04/01 12:48] (current) – [Some notes about NbtCompound] solidblock | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Modify BlockEntity data ====== | ====== Modify BlockEntity data ====== | ||
- | ===== Introduction ===== | + | In the previous tutorial, we have created a [[blockentity|block entity]]. But they are too boring as they do not have any data. Therefore, we try to add some data to it, and define ways of serializing and deserializing data. |
- | In the previous | + | ===== Some notes about NbtCompound ===== |
+ | |||
+ | Since 1.21.5, methods of '' | ||
+ | |||
+ | <code java> | ||
+ | // no default value specified, returns Optional | ||
+ | Optional< | ||
+ | |||
+ | // default value specified, returns the default value when the field does not exist | ||
+ | int value = nbt.getInt(" | ||
+ | </ | ||
+ | |||
+ | For collection types, such as compounds and lists, an empty object can be returned as a default value, for example: | ||
+ | <code java> | ||
+ | // no default value specified, returns Optional | ||
+ | Optional< | ||
+ | |||
+ | // when the field does not exist, returns an empty compound | ||
+ | NbtCompound config = nbt.getCompoundOrEmpty(" | ||
+ | </ | ||
+ | |||
+ | In versions before 1.21.5, they return zero or empty values. If you need to specify a default value, you need to judge with '' | ||
+ | <code java> | ||
+ | // returns 0 if the field does not exist: | ||
+ | int value = nbt.getInt(" | ||
+ | |||
+ | // returns an empty compound when the field does not exist: | ||
+ | NbtCompound config = nbt.getCompound(" | ||
+ | </ | ||
+ | |||
+ | Besides, since 1.21.5, the whole NBT compound and its fields can be decoded directly with [[codec]]s, such as: | ||
+ | <code java> | ||
+ | NbtCompound nbt = new NbtCompound(); | ||
+ | nbt.put(" | ||
+ | Optional< | ||
+ | </ | ||
+ | |||
+ | <code java> | ||
+ | NbtCompound nbt = new NbtCompound(); | ||
+ | // have to use the RegistryOps since an item is a registry entry | ||
+ | nbt.copyFromCodec(ItemStack.MAP_CODEC, | ||
+ | Optional< | ||
+ | </ | ||
+ | |||
+ | Besides, since 1.21.5, lists support mixing elements of different types. In previous versions, mixing elements of different types in a list results in exceptions. | ||
+ | |||
+ | More information about NBT changes, see [[https:// | ||
+ | ===== Serializing Data ===== | ||
+ | |||
+ | If you want to store any data in your '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | In older versions, it was very important to call '' | ||
+ | |||
+ | Knowing | ||
+ | |||
+ | <code java DemoBlockEntity.java> | ||
+ | public class DemoBlockEntity extends BlockEntity { | ||
+ | |||
+ | // Store the current value of the number | ||
+ | private int number = 0; | ||
+ | |||
+ | public DemoBlockEntity(BlockPos pos, BlockState state) { | ||
+ | super(TutorialBlockEntityTypes.DEMO_BLOCK, | ||
+ | } | ||
+ | |||
+ | // Serialize the BlockEntity | ||
+ | @Override | ||
+ | public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { | ||
+ | // Save the current value of the number to the nbt | ||
+ | nbt.putInt(" | ||
+ | |||
+ | super.writeNbt(nbt, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | In order to read the data, you will also need to override '' | ||
+ | |||
+ | <code java> | ||
+ | // Deserialize the BlockEntity | ||
+ | @Override | ||
+ | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registries) { | ||
+ | super.readNbt(nbt, | ||
+ | |||
+ | number = nbt.getInt(" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | To get the NBT data for the block entity, call '' | ||
+ | |||
+ | For old versions, calling '' | ||
+ | |||
+ | ===== Sync data from server to client ===== | ||
+ | The data is read in the server world usually. Most data are not needed by the client, for example, your client does not need to know what's in the chest or furnace, until you open the GUI. But for some block entities, such as signs and banners, you have to inform the client of the data of the block entity, for example, for rendering. | ||
+ | |||
+ | For version 1.17.1 and below, implement '' | ||
+ | |||
+ | For version 1.18 and above, override '' | ||
+ | <code java> | ||
+ | @Nullable | ||
+ | @Override | ||
+ | public Packet< | ||
+ | return BlockEntityUpdateS2CPacket.create(this); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { | ||
+ | return createNbt(registryLookup); | ||
+ | } | ||
+ | </ | ||
<code java DemoBlockEntity.class> | <code java DemoBlockEntity.class> | ||
Line 11: | Line 122: | ||
public DemoBlockEntity(BlockPos pos, BlockState state) { | public DemoBlockEntity(BlockPos pos, BlockState state) { | ||
- | super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); | + | super(TutorialBlockEntityTypes.DEMO_BLOCK, pos, state); |
} | } | ||
@Override | @Override | ||
- | public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup | + | public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup |
nbt.putInt(" | nbt.putInt(" | ||
- | super.writeNbt(nbt, | + | super.writeNbt(nbt, |
} | } | ||
| | ||
@Override | @Override | ||
- | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup | + | public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup |
- | super.readNbt(nbt); | + | super.readNbt(nbt, registries); |
- | number = nbt.getInt(" | + | |
+ | | ||
} | } | ||
} | } | ||
</ | </ | ||
- | Make sure the '' | + | Make sure the '' |
===== Modifying the data ===== | ===== Modifying the data ===== | ||
Line 48: | Line 160: | ||
demoBlockEntity.number++; | demoBlockEntity.number++; | ||
player.sendMessage(Text.literal(" | player.sendMessage(Text.literal(" | ||
+ | demoBlockEntity.markDirty(); | ||
} | } | ||
} | } | ||
| | ||
- | return ActionResult.success(world.isClient); | + | return ActionResult.SUCCESS; |
} | } | ||
} | } | ||
+ | </ | ||
+ | |||
+ | The method '' | ||
+ | |||
+ | If you want clients to know the update (for example, they may be need to render, or pick-stack without holding '' | ||
+ | <code java> | ||
+ | world.updateListeners(pos, | ||
</ | </ | ||
===== Using data components ===== | ===== Using data components ===== | ||
- | Since 1.20.5, you can also use data components to store data. In this case, as data components have codecs that can serialize and deserialize themselves, | + | Since 1.20.5, you can also use data components to store data. This is required if you want to write the data into item stacks. You still need to write '' |
- | If you want to have a try, //remove// the '' | + | Create |
- | <code java ExampleMod.java> | + | <code java TutorialDataComponentTypes.java> |
- | public static final ComponentType< | + | public class TutorialDataComponentTypes { |
+ | | ||
+ | .codec(Codec.INT) | ||
+ | .packetCodec(PacketCodecs.INTEGER)); | ||
+ | |||
+ | public static <T> ComponentType< | ||
+ | return | ||
+ | } | ||
+ | |||
+ | public static void initialize() { | ||
+ | } | ||
+ | } | ||
</ | </ | ||
- | > :!: Here for simplicity, we just place them in the '' | + | Remember to refer to the method |
+ | <code java ExampleMod.java> | ||
+ | public | ||
+ | [...] | ||
+ | |||
+ | @Override | ||
+ | public static void onInitialize() { | ||
+ | [..] | ||
+ | TutorialDataComponentTypes.initialize(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
And then in the block entity: | And then in the block entity: | ||
<code java DemoBlockEntity.java> | <code java DemoBlockEntity.java> | ||
- | // removed the `readNbt` and `writeNbt` methods. | ||
- | |||
@Override | @Override | ||
protected void readComponents(ComponentsAccess components) { | protected void readComponents(ComponentsAccess components) { | ||
Line 84: | Line 224: | ||
componentMapBuilder.add(ExampleMod.NUMBER, | componentMapBuilder.add(ExampleMod.NUMBER, | ||
} | } | ||
- | </ | ||
- | Now these components can also be stored normally. If you pick stack (which means press the mouse wheel to the block write pressing '' | + | @Override |
+ | public void removeFromCopiedStackNbt(NbtCompound nbt) { | ||
+ | nbt.remove(" | ||
+ | } | ||
+ | </ | ||
- | In some cases, you can also retain the '' | + | The usage of '' |
tutorial/blockentity_modify_data.1724632268.txt.gz · Last modified: 2024/08/26 00:31 by solidblock