def retrieve_nbt(filename): """ Attempt to read an NBT blob from the file with the given filename. If the requested file does not exist, then the returned tag will be empty and will be saved to that file when write_file() is called on the tag. This function can and will make a good effort to create intermediate directories as needed. XXX should handle corner cases XXX should mmap() when possible XXX should use Twisted's VFS :param str filename: NBT file to load :returns: `NBTFile` """ try: tag = NBTFile(filename) except IOError: # The hard way, huh? Wise guy... tag = NBTFile() tag.filename = filename try: # Make the directory holding this file. os.makedirs(os.path.normpath(os.path.split(filename)[0])) except OSError, e: if e.errno != EEXIST: raise
def save_to_tag(chunk): tag = NBTFile() tag.name = "" level = TAG_Compound() tag["Level"] = level level["Blocks"] = TAG_Byte_Array() level["HeightMap"] = TAG_Byte_Array() level["BlockLight"] = TAG_Byte_Array() level["Data"] = TAG_Byte_Array() level["SkyLight"] = TAG_Byte_Array() level["Blocks"].value = "".join(chr(i) for i in chunk.blocks.ravel()) level["HeightMap"].value = "".join(chr(i) for i in chunk.heightmap.ravel()) level["BlockLight"].value = "".join( pack_nibbles(chunk.blocklight.ravel())) level["Data"].value = "".join(pack_nibbles(chunk.metadata)) level["SkyLight"].value = "".join(pack_nibbles(chunk.skylight)) level["TerrainPopulated"] = TAG_Byte(chunk.populated) level["TileEntities"] = TAG_List(type=TAG_Compound) for tile in chunk.tiles.itervalues(): level["TileEntities"].tags.append(tile.save_to_tag()) return tag
def generate_level(): level = NBTFile() # Blank NBT level.name = "Data" level.tags.extend([ TAG_Long(name="Time", value=1), TAG_Long(name="LastPlayed", value=int(time.time())), TAG_Int(name="SpawnX", value=0), TAG_Int(name="SpawnY", value=2), TAG_Int(name="SpawnZ", value=0), TAG_Long(name="SizeOnDisk", value=0), TAG_Long(name="RandomSeed", value=random.randrange(1,9999999999)), TAG_Int(name="version", value=19132), TAG_String(name="LevelName", value="Testing") ]) player = TAG_Compound() player.name = "Player" player.tags.extend([ TAG_Int(name="Score", value=0), TAG_Int(name="Dimension", value=0) ]) inventory = TAG_Compound() inventory.name = "Inventory" player.tags.append(inventory) level.tags.append(player) return level
def generate_level(): level = NBTFile() # Blank NBT level.name = "Data" level.tags.extend([ TAG_Long(name="Time", value=1), TAG_Long(name="LastPlayed", value=int(time.time())), TAG_Int(name="SpawnX", value=0), TAG_Int(name="SpawnY", value=2), TAG_Int(name="SpawnZ", value=0), TAG_Long(name="SizeOnDisk", value=0), TAG_Long(name="RandomSeed", value=random.randrange(1, 9999999999)), TAG_Int(name="version", value=19132), Tag_String(name="LevelName", value="Testing") ]) player = Tag_Compound() player.name = "Player" player.tags.extend( [TAG_Int(name="Score", value=0), TAG_Int(name="Dimension", value=0)]) inventory = Tag_Compound() inventory.name = "Inventory" player.tags.append(inventory) level.tags.append(player) return level
def value(self): if self.type_ == list: tag = TAG_Compound(self.name) tag.tags = [x.value for x in self._value] return tag if self.type_ == NBTFile: x = NBTFile() x.name = self.name x.tags = [x.value for x in self._value] return x if self.type_ == TAG_Compound: tag = TAG_Compound(name=self.name) tag.tags = [x.value for x in self._value] tag.name = self.name return tag if self.type_ == TAG_Int_Array: tag = TAG_Int_Array(name=self.name) tag.value = self._value return tag if self.type_ == TAG_List: tag = TAG_List(type=self.extra, name=self.name) tag.tags = [x.value for x in self._value] tag.name = self.name return tag return self.type_(value=self._value, name=self.name)
def main(): # Read map files to sort by scale print("Reading map files...") mapfiles = [] for i in range(0,5): mapfiles.append([]) i = 0 while os.path.isfile(inputDir + "map_" + str(i) + ".dat"): # read file nbt = NBTFile(inputDir + "map_" + str(i) + ".dat") data = nbt["data"] if int(data["dimension"].value) == 0: scale = data["scale"].value print(" Map " + str(i)) mapfiles[scale].append(i) nbt = None i = i + 1 # Process map files in order of scaling, and build image print("Processing map files into image...") imgwidth = xmax - xmin imgheight = zmax - zmin img = Image.new('RGBA', (imgwidth, imgheight)) colormap = getcolormap() for s in reversed(range(0,5)): for i in mapfiles[s]: # get map info nbt = NBTFile(inputDir + "map_" + str(i) + ".dat") data = nbt["data"] scale = 2 ** int(data["scale"].value) cx = data["xCenter"].value - (64 * scale) cz = data["zCenter"].value - (64 * scale) print(" Map " + str(i) + ": Scale = " + str(scale) + ":1, Corner=" + str(cx) + "," + str(cz)) # get colors for mx in range(0,128): for mz in range(0,128): # color at map pixel colorindex = data["colors"][mx + mz * 128] if colorindex < 4: # unexplored continue color = colormap[colorindex] # iterate over actual world blocks for px in range(0,scale): for pz in range(0,scale): coords = (cx + (mx * scale) + px, cz + (mz * scale) + pz) imgx = coords[0] - xmin imgy = coords[1] - zmin if imgx >= 0 and imgx < imgwidth and imgy >= 0 and imgy < imgheight: img.putpixel((imgx,imgy), color) # clean up nbt = None data = None print("Saving image...") img.save(outputFile) print("Done!")
def save_to_tag(level): tag = NBTFile() tag.name = "" tag["Data"] = TAG_Compound() tag["Data"]["RandomSeed"] = TAG_Long(level.seed) tag["Data"]["SpawnX"] = TAG_Int(level.spawn[0]) tag["Data"]["SpawnY"] = TAG_Int(level.spawn[1]) tag["Data"]["SpawnZ"] = TAG_Int(level.spawn[2]) return tag
def unpack_raw(raw, export=False): """Unpack raw b64 encoded gzipped nbt data Steps: 1. Decode base 64 2. nbt.nbt.NBTFile(fileobj=io.BytesIO()) 3. Walk tree and return it as json/dict """ decoded = base64.b64decode(raw) nbtfile = NBTFile(fileobj=io.BytesIO(decoded)) if export: nbtfile.write_file( f'nbt{datetime.datetime.now().strftime("%Y%m%d-%H%M%S-%f.nbt")}') return
class EmptyStringTest(unittest.TestCase): def setUp(self): self.golden_value = b"\x0A\0\x04Test\x08\0\x0Cempty string\0\0\0" self.nbtfile = NBTFile(buffer=BytesIO(self.golden_value)) def testReadEmptyString(self): self.assertEqual(self.nbtfile.name, "Test") self.assertEqual(self.nbtfile["empty string"].value, "") def testWriteEmptyString(self): buffer = BytesIO() self.nbtfile.write_file(buffer=buffer) self.assertEqual(buffer.getvalue(), self.golden_value)
def save_to_tag(chest): tag = NBTFile() tag.name = "" tag["id"] = TAG_String("Chest") tag["x"] = TAG_Int(chest.x) tag["y"] = TAG_Int(chest.y) tag["z"] = TAG_Int(chest.z) tag["Items"] = chest.inventory.save_to_tag() return tag
def save_to_tag(player): tag = NBTFile() tag.name = "" tag["Pos"] = TAG_List(type=TAG_Double) tag["Pos"].tags = [TAG_Double(i) for i in (player.location.x, player.location.y, player.location.z)] tag["Rotation"] = TAG_List(type=TAG_Double) tag["Rotation"].tags = [TAG_Double(i) for i in (player.location.yaw, 0)] tag["Inventory"] = player.inventory.save_to_tag() return tag
def generate_level(bytesize=4): """Generate a level, which is a given size in bytes.""" level = NBTFile() # Blank NBT def append_byte_array(name, bytesize=1000): bytesize -= len(name) bytesize -= 7 # byte_array = TAG_Byte_Array(name=name, value=bytearray([random.randrange(256) for i in range(bytesize)])) # level.append(byte_array) byte_array = TAG_Byte_Array(name=name) byte_array.value = bytearray( [random.randrange(256) for i in range(bytesize)]) level.tags.append(byte_array) random.seed(123456789) # fixed seed to give predictable results. if bytesize < 13: raise ValueError("NBT file size is at least 13 bytes") # 4 bytes TAG_Compound overhead, 13 bytes TAG_Byte_Array overhead. bytesize -= 4 # deduce overhead bytes i = 1 while bytesize > 1500: append_byte_array("%06d" % i, 1000) i += 1 bytesize -= 1000 append_byte_array("last", bytesize) return level
def getnbt(filename): nbtdata = NBTFile(filename) unpackedData = unpack_nbt(nbtdata) #print(unpackedData) position = unpackedData["Pos"] dim = unpackedData["Dimension"] inv = unpackedData["Inventory"] ender = unpackedData["EnderItems"] (x1, y1, z1) = tuple(position) x1 = int(x1) y1 = int(y1) z1 = int(z1) def makeLine(item, source): item = dict(item) keyFilter = ["Count", "Slot", "id"] newItem = OrderedDict() newItem.update({"Source": source}) for key in sorted(item): if key in keyFilter: newItem.update({key: item[key]}) if key == "tag": if "display" in item["tag"]: if "Name" in item["tag"]["display"]: item.update( {"Name": item["tag"]["display"]["Name"]}) return json.dumps(newItem) invLines = [makeLine(a, "i") for a in inv] enderLines = [makeLine(a, "e") for a in ender] return (dim, x1, y1, z1, invLines, enderLines)
def __init__(self, server, folder): self.server = server self.folder = folder if not os.path.exists(folder) or not os.path.isdir(folder): print('The world folder is missing!') return self.levelData = NBTFile(filename=os.path.join(self.folder, 'level.dat'), buffer='rb') self.seed = self.levelData['Data']['RandomSeed'].value self.spawn = [ self.levelData['Data']['SpawnX'].value, self.levelData['Data']['SpawnY'].value, self.levelData['Data']['SpawnZ'].value ] self.chunks = {} self.test = False self.loadWorld() print 'Loaded %s chunks' % (len(self.chunks)) self.clients = [] self.time = 0 reactor.callLater(1, self.sendTime)
def scan(self): for file in listdir(self.args.world + '/playerdata/'): nbt = NBTFile(self.args.world + '/playerdata/' + file, 'rb') inv_items = nbt['Inventory'] ec_items = nbt['EnderItems'] if self.args.inventory and len(inv_items) != 0: for item in inv_items: _item = Item(item['id'].value, item['Count'].value, item['Damage'].value) if is_scan_item(self.args, _item) and _item.count >= self.args.count: print('Found {0}*{1} in {2}\'s inventory !'.format( _item.count, _item.material, file.replace('.dat', '') )) if self.args.enderchest and len(ec_items) != 0: for item in ec_items: _item = Item(item['id'].value, item['Count'].value, item['Damage'].value) if is_scan_item(self.args, _item) and _item.count > self.args.count: print('Found {0}*{1} in {2}\'s enderchest !'.format( _item.count, _item.material, file.replace('.dat', '') ))
def get_last_played_level(): mc_dir = SETTINGS.value("MinecraftDirectory", utils.get_default_minecraft_dir()) mc_saves = os.path.join(mc_dir, "saves") worlds_recently_modified = sorted( [os.path.join(mc_saves, s) for s in os.listdir(mc_saves)], key=os.path.getmtime, reverse=True) for world in worlds_recently_modified: try: level = NBTFile(os.path.join(world, "level.dat")) with open( os.path.join( world, "advancements", os.listdir(os.path.join(world, "advancements"))[0])) as f: advancements = dict(json.load(f)) break except: continue data = { "name": str(level["Data"]["LevelName"]), "version": str(level["Data"]["Version"]["Name"]), "dataversion": int(str(level["Data"]["DataVersion"])), "adv": advancements } return data
def getKoords(): level = NBTFile(LEVELDAT, 'rb') x = int(float(str(level["Data"]["Player"]["Pos"][0]))) y = int(float(str(level["Data"]["Player"]["Pos"][1]))) z = int(float(str(level["Data"]["Player"]["Pos"][2]))) print(f"x={x} y={y} z={z}") return x, y, z
def test01ReadChunk(self): """Test if a block can be read, even when the file is truncated right after the block data.""" data = self.region.get_blockdata( 0, 0) # This may raise a RegionFileFormatError. data = BytesIO(data) nbt = NBTFile(buffer=data) self.assertEqual(nbt["Time"].value, 1) self.assertEqual(nbt["Name"].value, "Test")
def main(world_folder, show=True): scorefile = world_folder + '/data/scoreboard.dat' scores = NBTFile(scorefile, 'rb') for player in scores["data"]["PlayerScores"]: print( "%s: %d %s" % (player["Name"], player["Score"].value, player["Objective"].value))
def testProperlyClosed(self): """ test that files opened from a file name are closed after being written to. i.e. will read correctly in the future """ #open the file mynbt = NBTFile(self.filename) mynbt['test'] = TAG_Int(123) mynbt.write_file() if hasattr(mynbt.file, "closed"): self.assertTrue(mynbt.file.closed) else: # GZipFile does not yet have a closed attribute in Python 2.6 self.assertTrue(mynbt.file.fileobj == None) # make sure it can be read again directly after closing, # and contains the updated contents. mynbt = NBTFile(self.filename) self.assertEqual(mynbt['test'].value, 123)
def save_to_tag(sign): tag = NBTFile() tag.name = "" tag["id"] = TAG_String("Sign") tag["x"] = TAG_Int(sign.x) tag["y"] = TAG_Int(sign.y) tag["z"] = TAG_Int(sign.z) tag["Text1"] = TAG_String(sign.text1) tag["Text2"] = TAG_String(sign.text2) tag["Text3"] = TAG_String(sign.text3) tag["Text4"] = TAG_String(sign.text4) return tag
def __loadMaps(self): """ Loads all the maps (which were crafted in game) Returns: list """ maps = [] for mapFile in glob.glob(os.path.join(self.__directory, '*.dat')): if not 'map_' in mapFile: continue mapContent = NBTFile(mapFile, 'rb') result = re.search('(map_\d+).dat', mapFile); maps.append(Map( result.group(1), int(str(mapContent.get('data').get('scale'))), int(str(mapContent.get('data').get('dimension'))), int(str(mapContent.get('data').get('width'))), int(str(mapContent.get('data').get('height'))), int(str(mapContent.get('data').get('xCenter'))), int(str(mapContent.get('data').get('zCenter'))), mapContent.get('data').get('colors'), os.path.getmtime(mapFile) )) return maps
def parseNBT(raw_data: Union[bytes, str]) -> NBTFile: r"""Parses NBT data from the API. :param raw_data: The raw encoded NBT data. :type raw_data: Union[bytes, str] :return: The decoded NBT data. :rtype: nbt.nbt.NBTFile""" data = NBTFile(fileobj=io.BytesIO(base64.b64decode(raw_data))) return data
def get_last_played_level(): mc_dir = SETTINGS.value("MinecraftDirectory", utils.get_default_minecraft_dir()) mc_saves = os.path.join(mc_dir, "saves") worlds_recently_modified = sorted([os.path.join(mc_saves, s) for s in os.listdir(mc_saves)], key=os.path.getmtime, reverse=True) for w in worlds_recently_modified.copy()[:5]: try: world = w level = NBTFile(os.path.join(world, "level.dat")) if not int(str(level["Data"]["Time"])): continue else: break except: continue try: with open(os.path.join(world, "stats", os.listdir(os.path.join(world, "stats"))[0]), "r") as f: stats = json.load(f) except: #* If it's pre 1.7.2 stats = None try: seen_credits = bool(int(str(level["Data"]["Player"]["seenCredits"]))) except: #* If it's pre 1.12 OR a server seen_credits = None try: data = { "name": str(level["Data"]["LevelName"]), "version": str(level["Data"]["Version"]["Name"]), "igt": stats["stat.playOneMinute"] if int(str(level["Data"]["DataVersion"])) < 1451 else stats["stats"]["minecraft:custom"]["minecraft:play_one_minute"], "seen_credits": seen_credits, "pre17": False } except: #* If it's pre 1.9 try: data = { "name": str(level["Data"]["LevelName"]), "version": "Pre 1.9", "igt": stats["stat.playOneMinute"], "seen_credits": seen_credits, "pre17": False } except: #* If it's pre 1.7.2 data = { "name": str(level["Data"]["LevelName"]), "version": "Pre 1.7.2", "igt": utils.get_pre17_igt(mc_dir), "seen_credits": seen_credits, "pre17": True } return data
def testProperlyClosed(self): """ test that files opened from a file name are closed after being written to. i.e. will read correctly in the future """ # copy the file (don't work on the original test file) tempdir = tempfile.mkdtemp() filename = os.path.join(tempdir, 'bigtest.nbt') shutil.copy(NBTTESTFILE, filename) #open the file f = NBTFile(filename) f.write_file() # make sure it can be read again directly after f = NBTFile(filename) # remove the temporary file try: shutil.rmtree(tempdir) except OSError as e: raise
def handleChunkFile(self, root, name): location = os.path.join(root, name) root = root.replace(self.folder, '')[1:] dirs = root.split(os.sep) if len(dirs) != 2: return a, b = dirs chunkFile = name.split('.') if len(chunkFile) != 4: print("Invalid chunk file: %s" % location) return if chunkFile[0] != 'c' or chunkFile[3] != 'dat': print("Invalid chunk file: %s" % location) return x, z = chunkFile[1], chunkFile[2] x, z = int(x, 36), int(z, 36) print("Loaded %s %s" % (x, z)) if a != base36(x & 63): print("Invalid chunk file: %s" % location) return if b != base36(z & 63): print("Invalid chunk file: %s" % location) return nbt = NBTFile(filename=location, buffer='rb') if x != nbt['Level']['xPos'].value: print("Invalid chunk file: %s" % location) return if z != nbt['Level']['zPos'].value: print("Invalid chunk file: %s" % location) return chunk = Chunk( self.server, self, x, z, nbt['Level']['TerrainPopulated'].value, nbt['Level']['Blocks'].value, nbt['Level']['Data'].value, nbt['Level']['BlockLight'].value, nbt['Level']['SkyLight'].value ) self.chunks[(chunkFile[1], chunkFile[2])] = chunk
def convert(nbt_file, function_file, settings): """ Converts an NBT structure files into an mcfunction file. `block_name_map` map can be used to change block name (for example when creating a bedrock function). Blocks are grouped into fills where possible. """ block_name_map = settings.get('block_name_map', {}) strip_namespace = settings.get('strip_namespace') structure = unpack_nbt(NBTFile(nbt_file, 'rb')) # create a list of mapped blocks blocks = [] for block in structure['blocks']: x, y, z = block['pos'] block_data = structure['palette'][block['state']] name = block_data['Name'] if strip_namespace: _, name = name.split(':') if 'Properties' in block_data: properties = [ f'{key}={value}' for key, value in block_data['Properties'].items() # any properties with `false` values are assumed to be default and are ignored if value != 'false' ] name = f"{name}[{','.join(properties)}]" # change the block name if a map exists if name in block_name_map: name = block_name_map[name] if name is not None: blocks.append((x, y, z, name)) # try to group contiguous blocks into fills fills = group_blocks_into_fills(blocks, structure['size']) if 'order_values' in settings: order_values = settings['order_values'] fills.sort(key=lambda f: order_values.get(f[2], 50)) # write out the function with open(function_file, 'w') as file: for min_voxel, max_voxel, name in fills: write_fill(file, min_voxel, max_voxel, name)
def main(world_folder, options): world = WorldFolder(world_folder) if not isinstance(world, nbt.world.AnvilWorldFolder): print(world_folder + " is not an Anvil world") return 0 level = NBTFile(os.path.join(world_folder, "level.dat")) version = Util.get_version(level) print("\nLoading level at " + world_folder) if version != "1.8" or options.force: if options.force: print("[Forcing level conversion attempt]") print("Level saved as Minecraft version " + version) try: total_nbt_edits = 0 total_block_edits = 0 for region in world.iter_regions(): for chunk in region.iter_chunks(): chunk, nbt_edits = convert_chunk(chunk) chunk, block_edits = convert_block(chunk) total_nbt_edits += nbt_edits total_block_edits += block_edits if options.save and nbt_edits > 0 or block_edits > 0: save_chunk(region, chunk) if total_nbt_edits > 0 or total_block_edits > 0: print("%d modifications made to the level nbt" % (total_nbt_edits)) print("%d modifications made to block section byte arrays" % (total_block_edits)) if options.save: save_level(level, world_folder) else: print("No modifications saved to level (using -n flag)") else: print("No level data was changed (nothing to modify)") except KeyboardInterrupt: return 75 else: print("Level is already saved for Minecraft 1.8 (or older)") if options.disable_keep_inv and options.save: disable_keep_inv(level, world_folder) return 0
def tree_to_nbt(nbt: Token, filename: str): nbt_file = NBTFile() nbt_file.tags = [x.value for x in nbt._value] # Fix this nbt_file.write_file(filename)
def setUp(self): self.nbtfile = NBTFile()
def setUp(self): self.golden_value = b"\x0A\0\x04Test\x08\0\x0Cempty string\0\0\0" self.nbtfile = NBTFile(buffer=BytesIO(self.golden_value))
position = [ bla.value for bla in nbtdata["Pos"] ] dimension = nbtdata["Dimension"].value UUIDleast = nbtdata["UUIDLeast"].value UUIDmost = nbtdata["UUIDMost"].value ''' def unpack_nbt(tag): """ Unpack an NBT tag into a native Python data structure. """ if isinstance(tag, TAG_List): return [unpack_nbt(i) for i in tag.tags] elif isinstance(tag, TAG_Compound): return dict((i.name, unpack_nbt(i)) for i in tag.tags) else: return tag.value for each in files: nbtData = NBTFile(each) pp = pprint.PrettyPrinter(depth=1, indent=4, width=10) Obj = unpack_nbt(nbtData) pp.pprint(Obj) #print([a["Players"] for a in Obj["data"]["Teams"] if a["Name"] == "mute"])
def testReadBig(self): mynbt = NBTFile(self.filename) self.assertTrue(mynbt.filename != None) self.assertEqual(len(mynbt.tags), 11)
def nbt_to_object(filename): ''' return an object from an NBT file''' nbtData = NBTFile(filename) return unpack_nbt(nbtData)
def nbt_to_json(filename: str, **dumps_kwargs: dict) -> str: nbt = NBTFile(filename) py = _to_py(nbt) return json.dumps(py.as_dict, **dumps_kwargs)
def testWriteback(self): mynbt = NBTFile(self.filename) mynbt.write_file()
def testWriteBig(self): mynbt = NBTFile(self.filename) output = BytesIO() mynbt.write_file(buffer=output) self.assertEqual(GzipFile(NBTTESTFILE).read(), output.getvalue())
def nbt_to_tree(filename: str) -> Token: nbt = NBTFile(filename) return _to_py(nbt)