def __init__(self, rect, heightmapTypes=[ "MOTION_BLOCKING", "MOTION_BLOCKING_NO_LEAVES", "OCEAN_FLOOR", "WORLD_SURFACE" ]): self.rect = rect self.chunkRect = (rect[0] >> 4, rect[1] >> 4, ((rect[0] + rect[2] - 1) >> 4) - (rect[0] >> 4) + 1, ((rect[1] + rect[3] - 1) >> 4) - (rect[1] >> 4) + 1) self.heightmapTypes = heightmapTypes bytes = getChunks(*self.chunkRect, rtype='bytes') file_like = BytesIO(bytes) print("parsing NBT") self.nbtfile = nbt.nbt.NBTFile(buffer=file_like) rectOffset = [rect[0] % 16, rect[1] % 16] # heightmaps self.heightmaps = {} for hmName in self.heightmapTypes: self.heightmaps[hmName] = np.zeros((rect[2], rect[3]), dtype=np.int) # Sections are in x,z,y order!!! (reverse minecraft order :p) self.sections = [[[None for i in range(16)] for z in range(self.chunkRect[3])] for x in range(self.chunkRect[2])] # heightmaps print("extracting heightmaps") for x in range(self.chunkRect[2]): for z in range(self.chunkRect[3]): chunkID = x + z * self.chunkRect[2] hms = self.nbtfile['Chunks'][chunkID]['Level']['Heightmaps'] for hmName in self.heightmapTypes: # hmRaw = hms['MOTION_BLOCKING'] hmRaw = hms[hmName] heightmapBitArray = BitArray(9, 16 * 16, hmRaw) heightmap = self.heightmaps[hmName] for cz in range(16): for cx in range(16): try: heightmap[-rectOffset[0] + x * 16 + cx, -rectOffset[1] + z * 16 + cz] = heightmapBitArray.getAt(cz * 16 + cx) except IndexError: pass # sections print("extracting chunk sections") for x in range(self.chunkRect[2]): for z in range(self.chunkRect[3]): chunkID = x + z * self.chunkRect[2] chunkSections = self.nbtfile['Chunks'][chunkID]['Level'][ 'Sections'] for section in chunkSections: y = section['Y'].value if not ('BlockStates' in section) or len( section['BlockStates']) == 0: continue palette = section['Palette'] rawBlockStates = section['BlockStates'] bitsPerEntry = max(4, ceil(log2(len(palette)))) blockStatesBitArray = BitArray(bitsPerEntry, 16 * 16 * 16, rawBlockStates) self.sections[x][z][y] = CachedSection( palette, blockStatesBitArray) print("done")
def __init__(self, x1, z1, x2, z2, heightmapTypes=["MOTION_BLOCKING", "MOTION_BLOCKING_NO_LEAVES", "OCEAN_FLOOR", "WORLD_SURFACE"]): """**Initialise WorldSlice with region and heightmaps**.""" self.rect = x1, z1, x2 - x1, z2 - z1 self.chunkRect = (self.rect[0] >> 4, self.rect[1] >> 4, ((self.rect[0] + self.rect[2] - 1) >> 4) - (self.rect[0] >> 4) + 1, ((self.rect[1] + self.rect[3] - 1) >> 4) - (self.rect[1] >> 4) + 1) self.heightmapTypes = heightmapTypes t0 = time.perf_counter() bytes = getChunks(*self.chunkRect, rtype='bytes') showPerf = False if showPerf: print(f"took {time.perf_counter() - t0}s") t0 = time.perf_counter() file_like = BytesIO(bytes) print("parsing NBT") self.nbtfile = nbt.nbt.NBTFile(buffer=file_like) if showPerf: print(f"took {time.perf_counter() - t0}s") t0 = time.perf_counter() rectOffset = [self.rect[0] % 16, self.rect[1] % 16] # heightmaps self.heightmaps = {} for hmName in self.heightmapTypes: self.heightmaps[hmName] = np.zeros( (self.rect[2], self.rect[3]), dtype=np.int) # Sections are in x,z,y order!!! (reverse minecraft order :p) self.sections = [[[None for i in range(16)] for z in range( self.chunkRect[3])] for x in range(self.chunkRect[2])] # heightmaps print("extracting heightmaps") for x in range(self.chunkRect[2]): for z in range(self.chunkRect[3]): chunkID = x + z * self.chunkRect[2] hms = self.nbtfile['Chunks'][chunkID]['Level']['Heightmaps'] for hmName in self.heightmapTypes: # hmRaw = hms['MOTION_BLOCKING'] hmRaw = hms[hmName] heightmapBitArray = BitArray(9, 16 * 16, hmRaw) heightmap = self.heightmaps[hmName] for cz in range(16): for cx in range(16): try: heightmap[-rectOffset[0] + x * 16 + cx, -rectOffset[1] + z * 16 + cz] \ = heightmapBitArray.getAt(cz * 16 + cx) except IndexError: pass if showPerf: print(f"took {time.perf_counter() - t0}s") t0 = time.perf_counter() # sections print("extracting chunk sections") for x in range(self.chunkRect[2]): for z in range(self.chunkRect[3]): chunkID = x + z * self.chunkRect[2] chunk = self.nbtfile['Chunks'][chunkID] chunkSections = chunk['Level']['Sections'] for section in chunkSections: y = section['Y'].value if (not ('BlockStates' in section) or len(section['BlockStates']) == 0): continue palette = section['Palette'] rawBlockStates = section['BlockStates'] bitsPerEntry = max(4, ceil(log2(len(palette)))) blockStatesBitArray = BitArray( bitsPerEntry, 16 * 16 * 16, rawBlockStates) self.sections[x][z][y] = CachedSection( palette, blockStatesBitArray) if showPerf: print(f"took {time.perf_counter() - t0}s") print("done")