def toNbt(self) -> nbt.TAG_Compound: data = nbt.TAG_Compound() motion = nbt.TAG_List(name="Motion", type=nbt.TAG_Double) motion.append(nbt.TAG_Double(self.velocity[0])) motion.append(nbt.TAG_Double(self.velocity[1])) motion.append(nbt.TAG_Double(self.velocity[2])) data.tags.append(motion) pos = nbt.TAG_List(name="Pos", type=nbt.TAG_Double) pos.append(nbt.TAG_Double(self.pos[0])) pos.append(nbt.TAG_Double(self.pos[1])) pos.append(nbt.TAG_Double(self.pos[2])) data.tags.append(pos) data.tags.append( nbt.TAG_String(name="id", value=f"minecraft:{self.kind.name}")) data.tags.append(nbt.TAG_Float(name="Health", value=self.health)) data.tags.append(nbt.TAG_Byte(name="OnGround", value=self.onGround)) data.tags.append( nbt.TAG_Int(name="PortalCooldown", value=self.portalCooldown)) if self.extra is not None: extra = self.extra.toNbt() data.tags += extra.tags return data
def norbert_parse_line(line, sep=DEFAULT_SEP): line = line.strip() name, tagtype, value = norbert_split_line(line, sep[2]) # validate user input if tagtype is None: err("Invalid or missing tag type: " + line) raise IOError(exceptions.INVALID_TYPE, "Not a norbert file") elif tagtype != nbt.TAG_COMPOUND and value is None: err("Tag value not found: " + line) raise IOError(exceptions.INVALID_VALUE, "Not a norbert file") # get the list of names/indexes names = norbert_split_name(name, sep) # create the tag if tagtype == nbt.TAG_LIST: listtype = tag_types[value] tag = nbt.TAG_List(type=nbt.TAGLIST[listtype]) elif tagtype == nbt.TAG_COMPOUND: tag = nbt.TAG_Compound() else: tag = nbt.TAGLIST[tagtype]() retval = set_tag(tag, value) if retval != 0: err("Invalid tag value: " + line) raise IOError(retval, "Not a norbert file") return names, tag
def norbert_add_tag(nbtfile, names, newtag): # give the root TAG_Compound the right name nbtfile.name = names[0] names.pop(0) tag = nbtfile for i, name in enumerate(names): testtag = get_tag(tag, str(name)) # tag already exists if testtag is not None: tag = testtag # add leaf node elif i + 1 == len(names): tag = norbert_add_child(tag, name, newtag) # add a list elif isinstance(names[i + 1], int): # list of basic tags if i + 2 == len(names): listtype = newtag.id # list of lists elif isinstance(names[i + 2], int): listtype = nbt.TAG_LIST # list of compounds else: listtype = nbt.TAG_COMPOUND tag = norbert_add_child(tag, name, \ nbt.TAG_List(type=nbt.TAGLIST[listtype]) ) # add a compound else: tag = norbert_add_child(tag, name, nbt.TAG_Compound())
def toNbt(entities: List[Entity]) -> nbt.TAG_List: result = nbt.TAG_List(type=nbt.TAG_Compound, name="Entities") for entity in entities: result.append(entity.toNbt()) return result
def template_village_file(tick): """ Creates a template villages.dat file that i can modify later on """ cat = nbt.NBTFile() cat2 = cat['data'] = nbt.TAG_Compound() cat2["Villages"] = nbt.TAG_List(Banana) cat2['Tick'] = nbt.TAG_Int(tick) return cat
def _as_schematic(self): nbtfile = nbt.NBTFile() nbtfile.name = "Schematic" nbtfile.tags.append(nbt.TAG_Short(name="Height", value=self.height)) nbtfile.tags.append(nbt.TAG_Short(name="Width", value=self.width)) nbtfile.tags.append(nbt.TAG_Short(name="Length", value=self.depth)) nbtfile.tags.append(nbt.TAG_Int(name="WEOffsetX", value=-1)) nbtfile.tags.append(nbt.TAG_Int(name="WEOffsetY", value=0)) nbtfile.tags.append(nbt.TAG_Int(name="WEOffsetZ", value=-1)) nbtfile.tags.append(nbt.TAG_Int(name="WEOriginX", value=0)) nbtfile.tags.append(nbt.TAG_Int(name="WEOriginY", value=0)) nbtfile.tags.append(nbt.TAG_Int(name="WEOriginZ", value=0)) # YZX ordering data = bytearray() blocks = bytearray() for y in range(self.height): for z in range(self.depth): for x in range(self.width): block_id, block_data = self.reader.get(x, y, z) blocks.append(block_id) data.append(block_data) blocks_tag = nbt.TAG_Byte_Array() blocks_tag.value = blocks data_tag = nbt.TAG_Byte_Array() data_tag.value = data nbtfile["Blocks"] = blocks_tag nbtfile["Data"] = data_tag nbtfile.tags.append(nbt.TAG_String(name="Materials", value=u"Alpha")) nbtfile["Entities"] = nbt.TAG_List(type=nbt.TAG_Compound) nbtfile["TileEntities"] = nbt.TAG_List(type=nbt.TAG_Compound) output = BytesIO() nbtfile.write_file(fileobj=output) as_nbt = output.getvalue() output.close() return as_nbt
def check_region_file(region_file, delete_entities=False, entity_limit=500): """ Takes a RegionFile obj and returns a list of corrupted chunks where each element represents a corrupted chunk and contains a tuple: (region file, coord x, coord y) and returns also the total number of chunks (including corrupted ones) """ total_chunks = 0 bad_chunks = [] wrong_located_chunks = [] try: for x in range(32): for z in range(32): #~ print "In chunk ({0},{1})".format(x,z) chunk = check_chunk(region_file, x, z) if isinstance(chunk, nbt.TAG_Compound): total_chunks += 1 total_entities = len(chunk['Level']['Entities'].tags) # deleting entities is here because to parse a chunk with thousands of wrong entities # takes a long time, and once detected is better to fix it at once. if delete_entities == True and total_entities > entity_limit: #~ print len(chunk['Level']['Entities'].tags) empty_tag_list = nbt.TAG_List(nbt.TAG_Byte, '', 'Entities') chunk['Level']['Entities'] = empty_tag_list #~ print len(chunk['Level']['Entities'].tags) print "Deleted {0} entities in chunk ({1},{2}).".format( total_entities, x, z) region_file.write_chunk(x, z, chunk) elif total_entities > entity_limit: print "[WARNING!]: The chunk ({0},{1}) in region file {2} has {3} entities, and this may be too much. This may be a problem!".format( x, z, region_file, total_entities) elif chunk == -1: total_chunks += 1 bad_chunks.append((region_file.filename, x, z)) elif chunk == -2: total_chunks += 1 wrong_located_chunks.append((region_file.filename, x, z)) # if None do nothing del chunk # unload chunk from memory filename = split(region_file.filename)[1] del region_file except KeyboardInterrupt: print "\nInterrupted by user\n" sys.exit(1) return filename, bad_chunks, wrong_located_chunks, total_chunks
def delete_entities(region_file, x, z): """ This function is used while scanning the world in scan.py! Takes a region file obj and a local chunks coords and deletes all the entities in that chunk. """ chunk = region_file.get_chunk(x, z) counter = len(chunk['Level']['Entities']) empty_tag_list = nbt.TAG_List(nbt.TAG_Byte, '', 'Entities') chunk['Level']['Entities'] = empty_tag_list region_file.write_chunk(x, z, chunk) return counter
def remove_chunk_entities(self, x, z): """ Takes a chunk coordinates, opens the chunk and removes all the entities in it. Return an integer with the number of entities removed""" region_file = region.RegionFile(self.path) chunk = region_file.get_chunk(x, z) counter = len(chunk['Level']['Entities']) empty_tag_list = nbt.TAG_List(nbt.TAG_Byte, '', 'Entities') chunk['Level']['Entities'] = empty_tag_list region_file.write_chunk(x, z, chunk) return counter
def save(self) -> nbt.NBTFile: """ Saves the chunk data to a :class:`NBTFile` Notes ----- Does not contain most data a regular chunk would have, but minecraft stills accept it. """ root = nbt.NBTFile() root.tags.append(nbt.TAG_Int(name='DataVersion', value=self.version)) level = nbt.TAG_Compound() # Needs to be in a separate line because it just gets # ignored if you pass it as a kwarg in the constructor level.name = 'Level' level.tags.extend([ nbt.TAG_List(name='Entities', type=nbt.TAG_Compound), nbt.TAG_List(name='TileEntities', type=nbt.TAG_Compound), nbt.TAG_List(name='LiquidTicks', type=nbt.TAG_Compound), nbt.TAG_Int(name='xPos', value=self.x), nbt.TAG_Int(name='zPos', value=self.z), nbt.TAG_Long(name='LastUpdate', value=0), nbt.TAG_Long(name='InhabitedTime', value=0), nbt.TAG_Byte(name='isLightOn', value=1), nbt.TAG_String(name='Status', value='full') ]) sections = nbt.TAG_List(name='Sections', type=nbt.TAG_Compound) for s in self.sections: if s: p = s.palette() # Minecraft does not save sections that are just air # So we can just skip them if len(p) == 1 and p[0].name() == 'minecraft:air': continue sections.tags.append(s.save()) level.tags.append(sections) root.tags.append(level) return root
def create_village(tick): """ Creates a template village """ village_template = nbt.TAG_Compound() village_template['Doors'] = nbt.TAG_List(Banana) village_template['Players'] = nbt.TAG_List(Banana) village_template['ACX'] = nbt.TAG_Int(0) village_template['ACY'] = nbt.TAG_Int(0) village_template['ACZ'] = nbt.TAG_Int(0) village_template['CX'] = nbt.TAG_Int(0) village_template['CY'] = nbt.TAG_Int(0) village_template['CZ'] = nbt.TAG_Int(0) village_template['Golems'] = nbt.TAG_Int(0) village_template['MTick'] = nbt.TAG_Int(0) village_template['PopSize'] = nbt.TAG_Int(1) village_template['Radius'] = nbt.TAG_Int(32) village_template['Stable'] = nbt.TAG_Int(tick) village_template['Tick'] = nbt.TAG_Int(tick) return Village(village_template)
def create_nbt_from_entry( entry: Union[NBTEntry, NBTListEntry, NBTCompoundEntry]) -> nbt.TAG: tag = None entry_type = entry.tag_type if entry_type in _entry_to_tag_map: tag = _entry_to_tag_map[entry_type](value=entry.value) elif isinstance(entry, NBTCompoundEntry): tag = nbt.TAG_Compound() for name, child_entry in entry.items(): tag[name] = create_nbt_from_entry(child_entry) elif isinstance(entry, NBTListEntry): tag = nbt.TAG_List() for child_entry in entry: tag.append(create_nbt_from_entry(child_entry)) return tag
def place_chests(self, region, new_region, x, y, z, direction): # add_x = 1 # add_z = 0 chest = anvil.Block("minecraft", "chest") chest.properties["waterlogged"] = "false" chest.properties["facing"] = "east" chest.properties["type"] = "single" # if direction == cfg.M_DIR_Z: # add_x = 0 # add_z = 1 # chest.properties["shape"] = "east_west" i = 0 chest_x = x chest_y = y - 1 chest_z = z for item_type in self.item_dict: amount = self.item_dict[item_type] while amount > 0: if direction == cfg.M_DIR_Z: chest_x = x + 1 chest_z = z + i else: chest_x = x + i chest_z = z + 1 new_region.set_block(chest, chest_x, chest_y, chest_z) item = "minecraft:" + str(item_type) block_entity, amount = self.create_chest_block_entity( chest_x, chest_y, chest_z, item, amount) chunk_idx_x = chest_x // cfg.CHUNK_B_X chunk_idx_z = chest_z // cfg.CHUNK_B_Z chunk = region.get_chunk(chunk_idx_x, chunk_idx_z) if chunk.data["TileEntities"].tagID != nbt.TAG_Compound.id: chunk.data["TileEntities"] = nbt.TAG_List( name="TileEntities", type=nbt.TAG_Compound) chunk.data["TileEntities"].tags.append(block_entity) i += 1
def get_chunk(self, chunk_x, chunk_z): key = (chunk_x, chunk_z) if not key in self.chunks: try: self.chunks[key] = self.region.get_chunk(chunk_x, chunk_z) except region.InconceivedChunk: # create the chunk new_chunk = nbt.NBTFile() level_tag = nbt.TAG_Compound() level_tag.name = "Level" level_tag.tags.append( nbt.TAG_Int(name="xPos", value=chunk_x * 32)) level_tag.tags.append( nbt.TAG_Int(name="zPos", value=chunk_z * 32)) level_tag.tags.append( nbt.TAG_List(name="Sections", type=nbt.TAG_Compound)) new_chunk.tags.append(level_tag) self.chunks[key] = new_chunk return self.chunks[key]
def create_chest_block_entity(self, chest_x, chest_y, chest_z, b_type, amount): items = nbt.TAG_List(name="Items", type=nbt.TAG_Compound) # TODO make this variable by using the config file stacks = min(amount // 64, 27) remainder = amount % 64 if stacks < 27 else 0 for i in range(stacks): chest_entry = nbt.TAG_Compound() chest_entry.tags.extend([ nbt.TAG_Byte(name="Count", value=64), nbt.TAG_Byte(name="Slot", value=i), nbt.TAG_String(name="id", value=b_type), ]) items.tags.append(chest_entry) if stacks < 27: chest_entry = nbt.TAG_Compound() chest_entry.tags.extend([ nbt.TAG_Byte(name="Count", value=amount % 64), nbt.TAG_Byte(name="Slot", value=stacks), nbt.TAG_String(name="id", value=b_type), ]) items.tags.append(chest_entry) block_entity = nbt.TAG_Compound() block_entity.tags.extend([ nbt.TAG_String(name="id", value="minecraft:chest"), nbt.TAG_Int(name="x", value=chest_x), nbt.TAG_Int(name="y", value=chest_y), nbt.TAG_Int(name="z", value=chest_z), nbt.TAG_Byte(name="keepPacked", value=0), ]) block_entity.tags.append(items) new_amount = amount - (stacks * 64 + remainder) return block_entity, new_amount
def toNbt(self) -> nbt.TAG_Compound: tag = super().toNbt() inventory = nbt.TAG_List(type=nbt.TAG_Compound, name='Inventory') for (slotIdx, item) in enumerate(self.inventory): stackTag = item.stack.toNbt(slotIdx) if stackTag is not None: inventory.append(stackTag) tag.tags.append(inventory) gameMode = 1 if self.creative else 0 tag.tags.append(nbt.TAG_Int(gameMode, 'playerGameType')) abilities = nbt.TAG_Compound() abilities.name = 'abilities' abilities.tags.append(nbt.TAG_Byte(int(self.flying), 'flying')) tag.tags.append(abilities) tag.tags.append(nbt.TAG_String(self.dimension, 'dimension')) return tag
def save_chunk(self, data) -> nbt.NBTFile: """ Saves the chunk data to a :class:`NBTFile` Notes ----- Does not contain most data a regular chunk would have, but minecraft stills accept it. """ root = nbt.NBTFile() root.tags.append(nbt.TAG_Int(name="DataVersion", value=self.version)) level = nbt.TAG_Compound() # Needs to be in a separate line because it just gets # ignored if you pass it as a kwarg in the constructor level.name = "Level" if data: if data.get("Biomes") is not None: level.tags.append(data["Biomes"]) if data.get("Heightmaps") is not None: level.tags.append(data["Heightmaps"]) # level.tags.append(data["CarvingMasks"]) if data.get("Entities") is not None: level.tags.append(data["Entities"]) if data.get("TileEntities") is not None: level.tags.append(data["TileEntities"]) # if data.get("TileTicks") is not None: # level.tags.append(data["TileTicks"]) if data.get("LiquidTicks") is not None: level.tags.append(data["LiquidTicks"]) ######## if data.get("Lights") is not None: level.tags.append(data["Lights"]) if data.get("LiquidsToBeTicked") is not None: level.tags.append(data["LiquidsToBeTicked"]) if data.get("ToBeTicked") is not None: level.tags.append(data["ToBeTicked"]) if data.get("CarvingMasks") is not None: level.tags.append(data["CarvingMasks"]) ########## if data.get("PostProcessing") is not None: level.tags.append(data["PostProcessing"]) if data.get("Structures") is not None: level.tags.append(data["Structures"]) level.tags.extend([ # nbt.TAG_List(name="Entities", type=nbt.TAG_Compound), # nbt.TAG_List(name="TileEntities", type=nbt.TAG_Compound), # nbt.TAG_List(name="LiquidTicks", type=nbt.TAG_Compound), nbt.TAG_Int(name="xPos", value=self.x), nbt.TAG_Int(name="zPos", value=self.z), # nbt.TAG_Long(name="LastUpdate", value=data["LastUpdate"]), nbt.TAG_Long(name="LastUpdate", value=0), # nbt.TAG_Long(name="InhabitedTime", value=data["InhabitedTime"]), nbt.TAG_Long(name="InhabitedTime", value=0), nbt.TAG_Byte(name="isLightOn", value=1), nbt.TAG_String(name="Status", value="full"), ]) # entities = self.add_entities(data["Entities"]) # level.tags.append(entities) # nbt.TAG_List(name="Entities", type=nbt.TAG_Compound) else: level.tags.extend([ # nbt.TAG_List(name="Entities", type=nbt.TAG_Compound), nbt.TAG_List(name="TileEntities", type=nbt.TAG_Compound), nbt.TAG_List(name="LiquidTicks", type=nbt.TAG_Compound), nbt.TAG_Int(name="xPos", value=self.x), nbt.TAG_Int(name="zPos", value=self.z), nbt.TAG_Long(name="LastUpdate", value=0), nbt.TAG_Long(name="InhabitedTime", value=0), nbt.TAG_Byte(name="isLightOn", value=1), nbt.TAG_String(name="Status", value="full"), ]) sections = nbt.TAG_List(name="Sections", type=nbt.TAG_Compound) for s in self.sections: if s: p = s.palette() # Minecraft does not save sections that are just air # So we can just skip them if len(p) == 1 and p[0].name() == "minecraft:air": continue sections.tags.append(s.save()) level.tags.append(sections) root.tags.append(level) return root
return template.default_value return NBTListEntry() else: return template.create_entry_from_template() template = loader.load_template(entity_id) entry = NBTCompoundEntry(convert_template(template)) return entry if __name__ == "__main__": print(create_entry_from_nbt(nbt.TAG_Byte(value=4))) compound = nbt.TAG_Compound() compound["test1"] = nbt.TAG_Int(value=-100) compound["test2"] = nbt.TAG_String(value="hello!") test1 = create_entry_from_nbt(compound) print(test1) print(create_nbt_from_entry(test1)) print("=" * 16) test2 = create_entry_from_nbt( nbt.TAG_List(value=[ nbt.TAG_String(value="test1"), nbt.TAG_String(value="test2"), nbt.TAG_String(value="test3"), ])) print(test2) print(create_nbt_from_entry(test2))
def make_tag_list(vals): tag = nbt.TAG_List(type=vals[0]) tag.tags = list(vals) return tag
def scan_mcr_file(region_file_path): """ Scans a region file reporting problems. Takes a RegionFile obj and returns a list of corrupted chunks where each element represents a corrupted chunk and is a tuple containing: (region file, (coord x, coord y), problem) This function is used from scan_all_mcr_files and uses a multiprocessing queue to return in real time info about the process. """ delete_entities = scan_mcr_file.options.delete_entities entity_limit = scan_mcr_file.options.entity_limit region_file = region.RegionFile(region_file_path) w = scan_mcr_file.w chunks = 0 problems = [] corrupted = 0 wrong = 0 entities_prob = 0 filename = split(region_file.filename)[1] try: for x in range(32): for z in range(32): chunk, status, error_msg = scan_chunk(region_file, x, z) if status == 0: chunks += 1 total_entities = len(chunk['Level']['Entities'].tags) # deleting entities is in here because to parse a chunk with thousands of wrong entities # takes a long time, and once detected is better to fix it at once. if total_entities >= entity_limit: if delete_entities == True: empty_tag_list = nbt.TAG_List(nbt.TAG_Byte,'','Entities') chunk['Level']['Entities'] = empty_tag_list print "Deleted {0} entities in chunk ({1},{2}).".format(total_entities, x, z) region_file.write_chunk(x, z, chunk) else: problems.append((region_file.filename,(x,z),w.TOO_MUCH_ENTITIES)) entities_prob += 1 print "[WARNING!]: The chunk ({0},{1}) in region file {2} has {3} entities, and this may be too much. This may be a problem!".format(x,z,split(region_file.filename)[1],total_entities) # This stores all the entities in a file, # comes handy sometimes. #~ pretty_tree = chunk['Level']['Entities'].pretty_tree() #~ name = "{2}.chunk.{0}.{1}.txt".format(x,z,split(region_file.filename)[1]) #~ archivo = open(name,'w') #~ archivo.write(pretty_tree) elif status == -1: chunks += 1 problems.append((region_file.filename,(x,z),w.CORRUPTED)) corrupted += 1 elif status == -2: chunks += 1 problems.append((region_file.filename,(x,z),w.WRONG_LOCATED)) wrong += 1 # if None do nothing del chunk # unload chunk from memory del region_file except KeyboardInterrupt: print "\nInterrupted by user\n" sys.exit(1) scan_mcr_file.q.put((filename, corrupted, wrong, entities_prob, chunks)) return problems