Guest User

Untitled

a guest
Apr 25th, 2018
492
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.21 KB | None | 0 0
  1. ## Block Storage & Network Protocol Changes
  2. Paletted chunks & removing BlockIDs brings a few big changes to how blocks are represented.
  3. In Bedrock, Blocks used to be represented by their 8 bit ID and 4 bit data; this means that we can only represent 256 blocks and 16 variants for each block. As it happens we ran out of IDs in Update Aquatic, so we had to do something about it :)
  4.  
  5. After this change, we can represent infinite types of Blocks and infinite BlockStates, just like in Java.
  6. BlockStates are what is sent over the network as they are roughly equivalent to the old ID+data information, eg. they're all the information attached to a block.
  7.  
  8. BlockStates are serialized in two ways:
  9.  
  10. **PersistentID**: a PersistentID is a NBT tag containing the BlockState name and its variant number; for example
  11. ```json
  12. {
  13. "name":"minecraft:log",
  14. "val":14
  15. }
  16. ```
  17. in the future it will contain the actual properties of the BlockState explicitly like in Java. This format is pretty expensive to serialize and send over the network though, so it isn't used in the protocol yet (and possibly never) but it might still be useful information for map makers :)
  18.  
  19. **RuntimeID**: a RuntimeID is an alternate ID that is used to refer to a BlockState within a game session. It's an unsigned int that is assigned to each new BlockState we discover when loading a world; worlds with different Behavior packs can (in the future) represent the same BlockState with different RuntimeIDs.
  20.  
  21. Because of this, you shouldn't ever write RuntimeIDs to disk or make them persist across game sessions, because they should change.
  22. A future version of the protocol will let the server send a `GlobalPalettePacket` which will let you tell the Client which block is which and have it install new blocks.
  23.  
  24. For the time being however, RuntimeIDs are actually static ( :( ) so you will have to use a lookup table to figure out which is which! The lookup table is appended at the end.
  25.  
  26. Typically, RuntimeIDs are serialized as `varint`s.
  27.  
  28. ### Item changes
  29.  
  30. We didn't do the same ID removal for Item, because Item's ID was a `short` already and so it wasn't as much of a concern; what we did was to move new blocks to negative IDs. So, every block past 256 will be -1, -2, -3 and so on.
  31.  
  32. This means that you can't compare Block IDs and Item IDs directly anymore, even if you keep Block IDs around!
  33.  
  34.  
  35. ### Changed packets
  36.  
  37. This is a (hopefully exhaustive) list of packets that changed and that your server should handle to talk with this version of Minecraft.
  38. If you're wondering where `FullChunkDataPacket` is, no worries! That one still supports the old format so you don't have to implement block palettes right away. Other packets aren't retrocompatible though, so you'll have to fix those:
  39.  
  40. - **UpdateBlockPacket**: BlockID -> RuntimeID
  41. - **LevelSoundEventPacket**: BlockID -> Data (which is a RuntimeID)
  42. - **LevelEventPacket**: the Data varint now represents a RuntimeID for `ParticlesDestroyBlock`, `ParticlesCrackBlock`, `ParticlesCropEaten` and `ParticlesDestroyArmorStand`.
  43. - **SetEntityDataPacket**: `Endermen` and `FallingBlock` use RuntimeID to represent their BlockState.
  44.  
  45. **FullChunkDataPacket**
  46. FullChunkDataPacket is an exception because it still understands the old format, as we needed to implement that anyway to read old worlds.
  47. Anyhow, you should start considering moving to the new format because until you do, you won't be able to send Blocks past 256 to the client!
  48.  
  49. Also, there's a small penalty to converting old chunks to new chunks on the client, so you should do that for speed as well.
  50.  
  51. ## The new SubChunk format
  52.  
  53. While the LevelChunk format itself is unchanged, what changed is the internal format of each SubChunk. The version is always a byte and there are a few valid `SubChunkFormat` versions:
  54.  
  55. - **1.2 format (versions 0,2,3,4,5,6,7)** The old format. It's just `[version:byte][16x16x16 blocks][16x16x16 data]`. There can be light information, but it will be discarded. Note how values 0,2,3,4,5,6,7 all mean this format! We had to do this because tools like MCEdit put those values in that field and we needed to keep those worlds working.
  56. - **Palettized format (version 1)** This format was introduced in 1.2.13 when palettization was initially implemented. The SubChunk just contains one block storage, so the format is `[version:byte][block storage]`
  57.  
  58. - **Palettized format with storage list (version 8)** This is the new Update Aquatic format, added to allow for several block storages. The additional block storage is used only for water for now, but we made the format generic.
  59. The format is `[version:byte][num_storages:byte][block storage1]...[blockStorageN]`
  60.  
  61.  
  62. ### Block Storage
  63.  
  64. A Block Storage is now its own type of object (different from SubChunk) with its own format and version! Don't put weird numbers in the version field this time :)
  65.  
  66. Block Storages are comprised primarily of a block-array and a palette. The block arrays store offsets which point to positions in the palette. These block arrays can have different types, each of which uses a different number of bits to represent each block. Valid types that the client understands are:
  67. ```cpp
  68. enum class Type : uint8_t {
  69. Paletted1 = 1, // 32 blocks per word, max 2 unique blockstates
  70. Paletted2 = 2, // 16 blocks per word, max 4 unique blockstates
  71. Paletted3 = 3, // 10 blocks and 2 bits of padding per word, max 8 unique blockstates
  72. Paletted4 = 4, // 8 blocks per word, max 16 unique blockstates
  73. Paletted5 = 5, // 6 blocks and 2 bits of padding per word, max 32 unique blockstates
  74. Paletted6 = 6, // 5 blocks and 2 bits of padding per word, max 64 unique blockstates
  75. Paletted8 = 8, // 4 blocks per word, max 256 unique blockstates
  76. Paletted16 = 16, // 2 blocks per word, max 65536 unique blockstates
  77. }
  78. ```
  79. These bits are stored in arrays of words. (A word is just a 4-byte unsigned int.)
  80. The number of blocks per word is `sizeof word in bits / bitsPerBlock`, where any remainder becomes unused padding bits on each word. Blocks never straddle words, so there are some unused bits in each word when word size doesn't divide exactly by the number of bits per block.
  81. Using less bits per block allows lowering memory usage, but also restricts the number of unique blockstates that can exist in a chunk.
  82.  
  83. #### Format
  84. - 1 byte: `(type << 1) | isRuntime)`
  85. - 7 bits: the blockstorage type from the enum above, i.e. the type of palette that the blockstorage is using. This one is used to select which subclass of BlockStateStorage to create.
  86. The padded formats are kind of nasty to implement but the good news are, you don't need to implement all of them (if you do, I suggest to use a template). The server can pick whatever format and the Client will understand it. Of course, if you waste space in the palettes you won't have the best compression.
  87. - 1 bit: whether the chunk is serialized for Runtime or for Persistence: always `1` when over the network.
  88. - `4096 / blocksPerWord ` words (plus `1` extra word in padded formats, e.g. for sizes 3,5 and 6): The actual blocks.
  89. - 1 varint: The palette size N
  90. - (for network) N varints: The palette entries, as RuntimeIDs. You should use the RuntimeID table to convert those to actual blocks.
  91. - (for persistence) N NBT tags: The palette entries, as PersistentIDs. You should read the "name" and "val" fields to figure out what blocks it represents.
Add Comment
Please, Sign In to add comment