def send_air_chunk(self, x, z): sections = [] if x == 0 and z == 0: sections = [(BlockArray.empty(self.registry), None) for _ in range(16)] sections[9][0][0] = {"name": "minecraft:bedrock"} sections_data = self.buff_type.pack_chunk(sections) motion_world = PackedArray.empty_height() motion_blocking = TagLongArray(PackedArray.empty_height()) world_surface = TagLongArray(PackedArray.empty_height()) heightmap = TagRoot({ "": TagCompound({ "MOTION_BLOCKING": motion_blocking, "WORLD_SURFACE": world_surface }) }) biomes = [27 for _ in range(1024)] block_entities = [] self.send_packet( "chunk_data", self.buff_type.pack("ii?", x, z, True), self.buff_type.pack_chunk_bitmask(sections), self.buff_type.pack_nbt(heightmap), # added in 1.14 self.buff_type.pack_varint(0), b"", # b"".join(self.buff_type.pack_varint(biome) for biome in biomes), # self.buff_type.pack_array("I", biomes), self.buff_type.pack_varint(len(sections_data)), sections_data, self.buff_type.pack_varint(len(block_entities)), b"" # b"".join(self.buff_type.pack_nbt(entity) for entity in block_entities), )
def mcaIterator(mca_path, mca_filename): registry = OpaqueRegistry(64) # log2(max block ID) with RegionFile(mca_path + mca_filename) as region_file: for chunk_x in range(0, 32): for chunk_z in range(0, 32): try: chunk = region_file.load_chunk(chunk_x, chunk_z) sections = chunk.value[''].value['Level'].value[ 'Sections'].value except (KeyError, ValueError, BufferUnderrun) as e: if type(e) is BufferUnderrun: print("Failed loading chunk:", chunk_x, chunk_z, "Reason:", type(e).__name__, e) continue for section in sections: try: blocks = BlockArray.from_nbt(section, registry) except KeyError as e: continue yield { 'mca': mca_filename, 'x': chunk_x, 'z': chunk_z, 'y': int.from_bytes(section.value['Y'].to_bytes(), 'big'), 'blocks': blocks, }
def test_chunk_internals(): blocks = BlockArray([0] * 4096, 4, [0]) # Accumulate blocks added = [] for i in range(300): block, meta = divmod(i, 16) blocks[i] = block, meta added.append((block, meta)) assert blocks[:i + 1] == added if i < 256: assert len(blocks.palette) == i + 1 if i < 16: assert blocks.bits == 4 elif i < 32: assert blocks.bits == 5 elif i < 64: assert blocks.bits == 6 elif i < 128: assert blocks.bits == 7 else: assert blocks.bits == 8 else: assert blocks.palette is None assert blocks.bits == 13 # Zero the first 100 blocks for i in range(100): blocks[i] = (0, 0) blocks.repack() assert len(blocks.palette) == 201 assert blocks.bits == 8 # Zero blocks 100-199 for i in range(100, 200): blocks[i] = (0, 0) blocks.repack() assert len(blocks.palette) == 101 assert blocks.bits == 7 # Zero blocks 205 - 300 for i in range(205, 300): blocks[i] = (0, 0) blocks.repack() assert len(blocks.palette) == 6 assert blocks.bits == 4 # Check value for i in range(4096): if 200 <= i < 205: assert blocks[i] == divmod(i, 16) else: assert blocks[i] == (0, 0)
def test_chunk_internals(): blocks = BlockArray(OpaqueBlockMap(13), [0] * 4096, 4, [0]) # Accumulate blocks added = [] for i in range(300): blocks[i] = i added.append(i) assert blocks[:i + 1] == added if i < 256: assert len(blocks.palette) == i + 1 if i < 16: assert blocks.bits == 4 elif i < 32: assert blocks.bits == 5 elif i < 64: assert blocks.bits == 6 elif i < 128: assert blocks.bits == 7 else: assert blocks.bits == 8 else: assert blocks.palette == [] assert blocks.bits == 13 # Zero the first 100 blocks for i in range(100): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 201 assert blocks.bits == 8 # Zero blocks 100-199 for i in range(100, 200): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 101 assert blocks.bits == 7 # Zero blocks 205 - 300 for i in range(205, 300): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 6 assert blocks.bits == 4 # Check value for i in range(4096): if 200 <= i < 205: assert blocks[i] == i else: assert blocks[i] == 0
def unpack_chunk_section(self): """ Unpacks a chunk section. Returns a sequence of length 4096 (16x16x16). """ non_air, bits = self.unpack('HB') palette = self.unpack_chunk_section_palette(bits) return BlockArray( self.registry, self.unpack_array('Q', self.unpack_varint()), bits, palette, non_air)
def unpack_chunk_section(self, overworld=True): """ Unpacks a chunk section. Returns a sequence of length 4096 (16x16x16). """ non_air, value_width = self.unpack('HB') palette = self.unpack_chunk_section_palette(value_width) array = self.unpack_chunk_section_array(value_width) return BlockArray.from_bytes(bytes=array, palette=palette, registry=self.registry, non_air=non_air, value_width=value_width), None, None
def test_chunk_internals(): blocks = BlockArray(OpaqueRegistry(13), [0]*4096, 4, [0]) # Accumulate blocks added = [] for i in range(300): blocks[i] = i added.append(i) assert blocks[:i+1] == added if i < 256: assert len(blocks.palette) == i + 1 if i < 16: assert blocks.bits == 4 elif i < 32: assert blocks.bits == 5 elif i < 64: assert blocks.bits == 6 elif i < 128: assert blocks.bits == 7 else: assert blocks.bits == 8 else: assert blocks.palette == [] assert blocks.bits == 13 # Zero the first 100 blocks for i in range(100): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 201 assert blocks.bits == 8 # Zero blocks 100-199 for i in range(100, 200): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 101 assert blocks.bits == 7 # Zero blocks 205 - 300 for i in range (205, 300): blocks[i] = 0 blocks.repack() assert len(blocks.palette) == 6 assert blocks.bits == 4 # Check value for i in range(4096): if 200 <= i < 205: assert blocks[i] == i else: assert blocks[i] == 0
def packet_downstream_chunk_data(self, buff): x, z, contiguous = buff.unpack('ii?') bitmask = buff.unpack_varint() size = buff.unpack_varint() if contiguous: chunk = self.chunks[x, z] = { 'sections': [None] * 16, 'block_entities': {}, 'block_actions': {}} else: chunk = self.chunks[x, z] for idx in range(16): if bitmask & (1 << idx): section = buff.unpack_chunk_section( self.dimension == 0) elif self.dimension == 0: section = (BlockArray.empty(buff.registry), LightArray.empty(), LightArray.empty()) else: section = (BlockArray.empty(buff.registry), LightArray.empty()) chunk['sections'][idx] = section if contiguous: chunk['biomes'] = buff.unpack('I' * 256) for _ in range(buff.unpack_varint()): block_entity = buff.unpack_nbt() block_entity_obj = block_entity.to_obj()[""] chunk['block_entities'][ block_entity_obj['x'], block_entity_obj['y'], block_entity_obj['z']] = block_entity
def test_wikivg_example(): # Example from https://wiki.vg/Chunk_Format#Example data = bitstring.BitArray(length=13 * 4096) data[ 0: 64] = '0b0000000000100000100001100011000101001000010000011000100001000001' data[ 64: 128] = '0b0000000100000001100010100111001001100000111101101000110010000111' data = data.bytes blocks = BlockArray.from_bytes(data, 5, OpaqueRegistry(13), []) assert blocks[:24] == [ 1, 2, 2, 3, 4, 4, 5, 6, 6, 4, 8, 0, 7, 4, 3, 13, 15, 16, 9, 14, 10, 12, 0, 2 ]
def test_wikivg_example(): # Example from https://wiki.vg/Chunk_Format#Example data = bitstring.BitArray(length=13*4096) data[0:64] = '0b0000000100000000000110001000000011000000000001100000000000100000' data[64:128] = '0b0000001000000000110100000000011010000000000001001100000000100000' data = data.bytes blocks = BlockArray.from_bytes(data, [], BitShiftRegistry(13), 10) assert blocks[0] == (2, 0) # grass assert blocks[1] == (3, 0) # dirt assert blocks[2] == (3, 0) # dirt assert blocks[3] == (3, 1) # coarse dirt assert blocks[4] == (1, 0) # stone assert blocks[5] == (1, 0) # stone assert blocks[6] == (1, 3) # diorite assert blocks[7] == (13, 0) # gravel assert blocks[8] == (13, 0) # gravel assert blocks[9] == (1, 0) # stone
def unpack_chunk_section(self, overworld=True): """ Unpacks a chunk section. Returns a 3-tuple of ``(blocks, block_lights, sky_lights)``, where *sky_lights* is ``None`` when *overworld* is ``False``. The returned values are sequences of length 4096 (16x16x16). """ bits = self.unpack('B') palette = self.unpack_chunk_section_palette(bits) blocks = BlockArray(self.registry, self.unpack_array('Q', self.unpack_varint()), bits, palette, None) block_lights = LightArray(self.unpack_array('B', 2048)) if overworld: sky_lights = LightArray(self.unpack_array('B', 2048)) else: sky_lights = None return blocks, block_lights, sky_lights
def unpack_chunk_section(self, overworld=True): """ Unpacks a chunk section from the buffer. Returns a 3-tuple of ``(blocks, block_lights, sky_lights)``, where *sky_lights* is ``None`` when *overworld* is ``False``. The returned values are sequences of length 4096 (16x16x16). """ bits = self.unpack('B') if bits < 4: bits = 4 elif bits > 8: bits = 13 palette = [self.unpack_varint() for _ in xrange(self.unpack_varint())] blocks = BlockArray(self.unpack('Q' * self.unpack_varint()), bits, palette) block_lights = LightArray(self.unpack('B' * 2048)) if overworld: sky_lights = LightArray(self.unpack('B' * 2048)) else: sky_lights = None return blocks, block_lights, sky_lights
def unpack_chunk_section(self, overworld=True): """ Unpacks a chunk section. Returns a 3-tuple of ``(blocks, block_lights, sky_lights)``, where *sky_lights* is ``None`` when *overworld* is ``False``. The returned values are sequences of length 4096 (16x16x16). """ value_width = self.unpack('B') palette = self.unpack_chunk_section_palette(value_width) array = self.unpack_chunk_section_array(value_width) blocks = BlockArray.from_bytes(bytes=array, palette=palette, registry=self.registry, non_air=None, value_width=value_width) block_lights = PackedArray.from_light_bytes(self.read(2048)) if overworld: sky_lights = PackedArray.from_light_bytes(self.read(2048)) else: sky_lights = None return blocks, block_lights, sky_lights
def parse_region_file(file, search_blocks): print("Start processing", file) search_results = [] with RegionFile(file) as region: for x, z in range_xz(0, 32): try: chunk = region.load_chunk(x, z) x_pos = chunk.body.value["Level"].value['xPos'].value z_pos = chunk.body.value["Level"].value['zPos'].value sections = chunk.body.value["Level"].value["Sections"].value for section in sections: blocks = BlockArray( registry, section.value["Blocks"].value, bits=8, ) y_pos = section.value['Y'].value for i in range(4096): block_id = blocks.data[i] if block_id in search_blocks: block_x = x_pos * 16 + i % 16 block_y = y_pos * 16 + i // 256 block_z = z_pos * 16 + i % 256 // 16 print( "Block found on index %s on coordinates %s, %s, %s" % (i, block_x, block_y, block_z)) search_results.append( (block_id, block_x, block_y, block_z)) except Exception: # pylint: disable=broad-except # catch any occurring errors to prevent script from stopping somewhere parsing the world pass print("Completed processing", file) return search_results