|
| 1 | +#include "section_format.hpp" |
| 2 | + |
| 3 | +namespace mcmap { |
| 4 | +namespace versions { |
| 5 | +namespace block_states_versions { |
| 6 | +void post116(const uint8_t index_length, |
| 7 | + const std::vector<int64_t> *blockStates, |
| 8 | + Section::block_array &buffer) { |
| 9 | + // NEW in 1.16, longs are padded by 0s when a block cannot fit, so no more |
| 10 | + // overflow to deal with ! |
| 11 | + |
| 12 | + for (uint16_t index = 0; index < 4096; index++) { |
| 13 | + // Determine how many indexes each long holds |
| 14 | + const uint8_t blocksPerLong = 64 / index_length; |
| 15 | + |
| 16 | + // Calculate where in the long array is the long containing the right index. |
| 17 | + const uint16_t longIndex = index / blocksPerLong; |
| 18 | + |
| 19 | + // Once we located a long, we have to know where in the 64 bits |
| 20 | + // the relevant block is located. |
| 21 | + const uint8_t padding = (index - longIndex * blocksPerLong) * index_length; |
| 22 | + |
| 23 | + // Bring the data to the first bits of the long, then extract it by bitwise |
| 24 | + // comparison |
| 25 | + const uint16_t blockIndex = ((*blockStates)[longIndex] >> padding) & |
| 26 | + ((uint64_t(1) << index_length) - 1); |
| 27 | + |
| 28 | + buffer[index] = blockIndex; |
| 29 | + } |
| 30 | +} |
| 31 | + |
| 32 | +void pre116(const uint8_t index_length, const std::vector<int64_t> *blockStates, |
| 33 | + Section::block_array &buffer) { |
| 34 | + // The `BlockStates` array contains data on the section's blocks. You have to |
| 35 | + // extract it by understanfing its structure. |
| 36 | + // |
| 37 | + // Although it is a array of long values, one must see it as an array of block |
| 38 | + // indexes, whose element size depends on the size of the Palette. This |
| 39 | + // routine locates the necessary long, extracts the block with bit |
| 40 | + // comparisons. |
| 41 | + // |
| 42 | + // The length of a block index has to be coded on the minimal possible size, |
| 43 | + // which is the logarithm in base2 of the size of the palette, or 4 if the |
| 44 | + // logarithm is smaller. |
| 45 | + |
| 46 | + for (uint16_t index = 0; index < 4096; index++) { |
| 47 | + |
| 48 | + // We skip the `position` first blocks, of length `size`, then divide by 64 |
| 49 | + // to get the number of longs to skip from the array |
| 50 | + const uint16_t skip_longs = (index * index_length) >> 6; |
| 51 | + |
| 52 | + // Once we located the data in a long, we have to know where in the 64 bits |
| 53 | + // it is located. This is the remaining of the previous operation |
| 54 | + const int8_t padding = (index * index_length) & 63; |
| 55 | + |
| 56 | + // Sometimes the data of an index does not fit entirely into a long, so we |
| 57 | + // check if there is overflow |
| 58 | + const int8_t overflow = |
| 59 | + (padding + index_length > 64 ? padding + index_length - 64 : 0); |
| 60 | + |
| 61 | + // This complicated expression extracts the necessary bits from the current |
| 62 | + // long. |
| 63 | + // |
| 64 | + // Lets say we need the following bits in a long (not to scale): |
| 65 | + // 10011100111001110011100 |
| 66 | + // ^^^^^ |
| 67 | + // We do this by shifting (>>) the data by padding, to get the relevant bits |
| 68 | + // on the end of the long: |
| 69 | + // ???????????????10011100 |
| 70 | + // ^^^^^ |
| 71 | + // We then apply a mask to get only the relevant bits: |
| 72 | + // ???????????????10011100 |
| 73 | + // 00000000000000000011111 & |
| 74 | + // 00000000000000000011100 <- result |
| 75 | + // |
| 76 | + // The mask is made at the size of the data, using the formula (1 << n) - 1, |
| 77 | + // the resulting bitset is of the following shape: 0...01...1 with n 1s. |
| 78 | + // |
| 79 | + // If there is an overflow, the mask size is reduced, as not to catch noise |
| 80 | + // from the padding (ie the interrogation points earlier) that appear on |
| 81 | + // ARM32. |
| 82 | + uint16_t lower_data = ((*blockStates)[skip_longs] >> padding) & |
| 83 | + ((uint64_t(1) << (index_length - overflow)) - 1); |
| 84 | + |
| 85 | + if (overflow > 0) { |
| 86 | + // The exact same process is used to catch the overflow from the next long |
| 87 | + const uint16_t upper_data = |
| 88 | + ((*blockStates)[skip_longs + 1]) & ((uint64_t(1) << overflow) - 1); |
| 89 | + // We then associate both values to create the final value |
| 90 | + lower_data = lower_data | (upper_data << (index_length - overflow)); |
| 91 | + } |
| 92 | + |
| 93 | + // lower_data now contains the index in the palette |
| 94 | + buffer[index] = lower_data; |
| 95 | + } |
| 96 | +} |
| 97 | +} // namespace block_states_versions |
| 98 | + |
| 99 | +namespace init_versions { |
| 100 | +void v1628(Section *target, const nbt::NBT &raw_section) { |
| 101 | + if (raw_section.contains("BlockStates") && raw_section.contains("Palette")) { |
| 102 | + target->palette = |
| 103 | + *raw_section["Palette"].get<const std::vector<nbt::NBT> *>(); |
| 104 | + const nbt::NBT::tag_long_array_t *blockStates = |
| 105 | + raw_section["BlockStates"].get<const nbt::NBT::tag_long_array_t *>(); |
| 106 | + |
| 107 | + // Remove the air that is default-constructed |
| 108 | + target->colors.clear(); |
| 109 | + // Anticipate the color input from the palette's size |
| 110 | + target->colors.reserve(target->palette.size()); |
| 111 | + |
| 112 | + // The length in bits of a block is the log2 of the palette's size or 4, |
| 113 | + // whichever is greatest. Ranges from 4 to 12. |
| 114 | + const uint8_t blockBitLength = |
| 115 | + std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4)); |
| 116 | + |
| 117 | + // Parse the blockstates for block info |
| 118 | + block_states_versions::pre116(blockBitLength, blockStates, target->blocks); |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +void v2534(Section *target, const nbt::NBT &raw_section) { |
| 123 | + if (raw_section.contains("BlockStates") && raw_section.contains("Palette")) { |
| 124 | + target->palette = |
| 125 | + *raw_section["Palette"].get<const std::vector<nbt::NBT> *>(); |
| 126 | + const nbt::NBT::tag_long_array_t *blockStates = |
| 127 | + raw_section["BlockStates"].get<const nbt::NBT::tag_long_array_t *>(); |
| 128 | + |
| 129 | + // Remove the air that is default-constructed |
| 130 | + target->colors.clear(); |
| 131 | + // Anticipate the color input from the palette's size |
| 132 | + target->colors.reserve(target->palette.size()); |
| 133 | + |
| 134 | + // The length in bits of a block is the log2 of the palette's size or 4, |
| 135 | + // whichever is greatest. Ranges from 4 to 12. |
| 136 | + const uint8_t blockBitLength = |
| 137 | + std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4)); |
| 138 | + |
| 139 | + // Parse the blockstates for block info |
| 140 | + block_states_versions::post116(blockBitLength, blockStates, target->blocks); |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +#ifdef SNAPSHOT_SUPPORT |
| 145 | +void v2840(Section *target, const nbt::NBT &raw_section) { |
| 146 | + if (raw_section.contains("block_states") && |
| 147 | + raw_section["block_states"].contains("data") && |
| 148 | + raw_section["block_states"].contains("palette")) { |
| 149 | + target->palette = *raw_section["block_states"]["palette"] |
| 150 | + .get<const std::vector<nbt::NBT> *>(); |
| 151 | + const nbt::NBT::tag_long_array_t *blockStates = |
| 152 | + raw_section["block_states"]["data"] |
| 153 | + .get<const nbt::NBT::tag_long_array_t *>(); |
| 154 | + |
| 155 | + // Remove the air that is default-constructed |
| 156 | + target->colors.clear(); |
| 157 | + // Anticipate the color input from the palette's size |
| 158 | + target->colors.reserve(target->palette.size()); |
| 159 | + |
| 160 | + // The length in bits of a block is the log2 of the palette's size or 4, |
| 161 | + // whichever is greatest. Ranges from 4 to 12. |
| 162 | + const uint8_t blockBitLength = |
| 163 | + std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4)); |
| 164 | + |
| 165 | + // Parse the blockstates for block info |
| 166 | + block_states_versions::post116(blockBitLength, blockStates, target->blocks); |
| 167 | + } |
| 168 | +} |
| 169 | +#endif |
| 170 | + |
| 171 | +void catchall(Section *, const nbt::NBT &) { |
| 172 | + logger::deep_debug("Unsupported DataVersion\n"); |
| 173 | +} |
| 174 | +} // namespace init_versions |
| 175 | +} // namespace versions |
| 176 | +} // namespace mcmap |
0 commit comments