async def finish_join(r: StreamReader, w: StreamWriter, remote: tuple) -> None: lvl_name = share["conf"]["level_name"] entity_id = entity_id_cache.get(remote) if entity_id is None: entity_id = entity_id_cache[remote] = int(time.time()) w.write( Buffer.pack_packet( packets_player.PlayJoinGame( entity_id, share["conf"]["hardcore"], 0, # Shoudl be current gamemode -1, # Should be previous gamemode # Should be actual world names [f"minecraft:{lvl_name}", f"minecraft:{lvl_name}_nether", f"minecraft:{lvl_name}_the_end"], nbt.TAG_Int(name="bruh", value=1), nbt.TAG_Int(name="bruh", value=1), f"minecraft:{lvl_name}", # should be actual current world name seed_hash(share["conf"]["seed"]), share["conf"]["max_players"], share["conf"]["view_distance"], (not share["conf"]["debug"]), True, # should be (not doImmediateRespawn gamerule) False, False, # Should be true if world is superflat ) ) ) await w.drain()
def generate_schematic(data, layout, blank_name, name, low_state, high_state) -> None: blankschem = nbt.NBTFile(blank_name, "rb") nbtfile = nbt.NBTFile() nbtfile.name = "Schematic" nbtfile, low_id, high_id = generate_palette(nbtfile, blankschem, low_state, high_state) Width, Lenght, Height = get_dimensions(blankschem) nbtfile.tags.extend([ nbt.TAG_Int(name="DataVersion", value=blankschem["DataVersion"].value), nbt.TAG_Int(name="Version", value=blankschem["Version"].value), nbt.TAG_Short(name="Length", value=Lenght), nbt.TAG_Short(name="Height", value=Height), nbt.TAG_Short(name="Width", value=Width), nbt.TAG_Int_Array(name="Offset"), ]) nbtfile = generate_meta(nbtfile, blankschem) nbtfile.tags.append(nbt.TAG_Byte_Array(name="BlockData")) nbtfile["BlockData"].value = generate_block_data(data, layout, blankschem, high_id, low_id) nbtfile.write_file(name)
def generate_palette(nbtfile: nbt.NBTFile, blankschem: nbt.NBTFile, low_state: str, high_state: str): blankpalette = {k: v.value for k, v in blankschem["Palette"].items()} palette = nbt.TAG_Compound(name="Palette") palette.name = "Palette" for name, id in blankpalette.items(): palette.tags.append(nbt.TAG_Int(name=name, value=id)) to_check = max(blankpalette.values()) + 2 # Find id of low state (create new if it is not present in palette) if low_state not in blankpalette: low_id = min(x for x in range(to_check) if x not in blankpalette.values()) palette.tags.append(nbt.TAG_Int(name=low_state, value=low_id)) else: low_id = blankpalette[low_state] # Find id of high state (create new if it is not present in palette) if high_state not in blankpalette: high_id = min(x for x in range(to_check) if x not in blankpalette.values()) palette.tags.append(nbt.TAG_Int(name=high_state, value=high_id)) else: high_id = blankpalette[high_state] nbtfile.tags.append(palette) nbtfile.tags.append(nbt.TAG_Int(name="PaletteMax", value=len(palette))) return nbtfile, low_id, high_id
def create_door(tick, x, y, z): """ Generates a door using given coords and tick. """ door = nbt.TAG_Compound() door['TS'] = nbt.TAG_Int(tick) door['X'] = nbt.TAG_Int(x) door['Y'] = nbt.TAG_Int(y) door['Z'] = nbt.TAG_Int(z) return door
def _update_doormath(self, x, y, z): doors_list = self._village['Doors'] self._village['ACX'].value += x self._village['ACY'].value += y self._village['ACZ'].value += z if len(doors_list) == 0: self._village['CX'] = nbt.TAG_Int(0) self._village['CY'] = nbt.TAG_Int(0) self._village['CZ'] = nbt.TAG_Int(0) else: self._village['CX'].value = self._village['ACX'].value / len( doors_list) self._village['CY'].value = self._village['ACY'].value / len( doors_list) self._village['CZ'].value = self._village['ACZ'].value / len( doors_list)
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 check_version_leveldat( root_tag: nbt.TAG_Compound, _min: int = None, _max: int = None ) -> bool: """ Check the Version tag from the provided level.dat NBT structure :param root_tag: the root level.dat tag :param _min: The lowest acceptable value (optional) :param _max: The highest acceptable value (optional) :return: Whether the version tag falls in the correct range """ version_found: int = root_tag.get("Data", nbt.TAG_Compound()).get( "Version", nbt.TAG_Compound() ).get("Id", nbt.TAG_Int(-1)).value min_qualifies: bool = True if _min is not None: min_qualifies = version_found >= _min max_qualifies: bool = True if _max is not None: max_qualifies = version_found <= _max if __debug__: min_text: str = f"{min} <= " if _min is not None else "" max_text: str = f" <= {max}" if _max is not None else "" print(f"Checking {min_text}{version_found}{max_text}") return min_qualifies and max_qualifies
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 gendefaultnbt(self): '''returns an nbt object''' nbtfile = nbt.NBTFile() colors = nbt.TAG_Byte_Array(name="colors") colors.value = bytearray(16384) data = nbt.TAG_Compound() data.name = "data" data.tags = [ nbt.TAG_Int(value=0, name="zCenter"), nbt.TAG_Byte(value=1, name="trackingPosition"), nbt.TAG_Short(value=128, name="width"), nbt.TAG_Byte(value=1, name="scale"), nbt.TAG_Byte(value=0, name="dimension"), nbt.TAG_Int(value=64, name="xCenter"), colors, nbt.TAG_Short(value=128, name="height") ] nbtfile.tags.append(data) return nbtfile
def save_to_nbtfile(barray, map_id): nbtfile = nbt.NBTFile() colors = nbt.TAG_Byte_Array(name="colors") colors.value = barray data = nbt.TAG_Compound() data.name = "data" data.tags = [ nbt.TAG_Byte(value=1, name="scale"), #地图缩放 nbt.TAG_Byte(value=0, name="dimension"), #维度 nbt.TAG_Byte(value=0, name="trackingPosition"), #箭头永不显示 nbt.TAG_Byte(value=1, name="locked"), #被锁定 nbt.TAG_Int(value=0, name="xCenter"), nbt.TAG_Int(value=0, name="zCenter"), nbt.TAG_Short(value=128, name="width"), nbt.TAG_Short(value=128, name="height"), colors ] nbtfile.tags.append(data) nbtfile.write_file("server/world/data/map_{}.dat".format(map_id))
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 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 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 _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 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
def setDimension(self, d): self.nbtfile['Dimension'] = nbt.TAG_Int(d)
def to_schem(img_path): # Open file and convert to RGB im = Image.open(img_path) rgb_im = im.convert('RGBA') blockjson = json.load(open('block.json')) palette_blocks = [] indices = {} # Creating palette palette = nbt.TAG_Compound() palette.name = 'Palette' # Initializing new NBT genfile = nbt.NBTFile() genfile.name = 'Schematic' # Setting basic NBT values genfile.tags.append(nbt.TAG_Int(name='Version', value=2)) genfile.tags.append(nbt.TAG_Short(name='Width', value=im.size[0])) genfile.tags.append(nbt.TAG_Short(name='Height', value=1)) genfile.tags.append(nbt.TAG_Short(name='Length', value=im.size[1])) genfile.tags.append(nbt.TAG_Int(name='DataVersion', value=2230)) # Creating block data blockdata = nbt.TAG_Byte_Array() blockdata.name = 'BlockData' # Iterating over each coordinate in the image for c in [(x, z) for x in range(im.size[0]) for z in range(im.size[1])]: # Get the color data from the pixel at coord c rgb = rgb_im.getpixel(c) # Getting the block with the closest color to the image pixel and # appending it to the palette list closest = min(blockjson, key=lambda k: math.dist(rgb, blockjson[k])) if closest not in palette_blocks: palette_blocks.append(closest) # The palette holds all the blocks that are used in a schematic. The field name # is the block name and the value is the index. This index is referenced in the # BlockData field to identify which block is present at a given coord palette[f'minecraft:{closest}'] = nbt.TAG_Int( value=palette_blocks.index(closest)) # Index blocks by x + z * Width + y * Width * Length. If we keep the same # order as the image coordinates the image comes out flipped. indices[c[0] + c[1] * im.size[0] + 1 * im.size[0] * im.size[1]] = palette_blocks.index(closest) # Set the palette length to length of the de-duped palette list genfile.tags.append( nbt.TAG_Int(name='PaletteMax', value=len(palette_blocks))) genfile.tags.append(palette) # A list of integers each referencing a block index from the palette is created # by sorting the indices dict. This list is then turned into a byte array as # that is the type needed by the NBT file. This prevents the image from being # flipped. blockdata.value = bytearray([indices[i] for i in sorted(indices)]) genfile.tags.append(blockdata) return genfile
STR_Long_Array = matchNumList('L') STR_List = delimited( pp.delimitedList(STR_TAG).setParseAction(lambda t: tuple(t)), start='[', end=']') STR_Compound = matchDict(STR_String, STR_TAG) STR_TAG << (STR_Number | STR_String | STR_Byte_Array | STR_Int_Array | STR_Long_Array | STR_List | STR_Compound) # ---------------------------------------------------------------------- STR_Byte.addParseAction(lambda t: nbt.TAG_Byte(t[0])) STR_Short.addParseAction(lambda t: nbt.TAG_Short(t[0])) STR_Int.addParseAction(lambda t: nbt.TAG_Int(t[0])) STR_Long.addParseAction(lambda t: nbt.TAG_Long(t[0])) STR_Float.addParseAction(lambda t: nbt.TAG_Float(t[0])) STR_Double.addParseAction(lambda t: nbt.TAG_Double(t[0])) STR_String.addParseAction(lambda t: nbt.TAG_String(t[0])) def make_tag_array(vals, tag_type, value_constructor=list): tag = tag_type() tag.value = value_constructor(vals) return tag STR_Byte_Array.addParseAction(lambda t: make_tag_array( t[0], nbt.TAG_Byte_Array, value_constructor=bytearray)) STR_Int_Array.addParseAction(lambda t: make_tag_array(t[0], nbt.TAG_Int_Array))
def save(self, file: Union[str, BinaryIO] = None) -> bytes: """ Returns the region as bytes with the anvil file format structure, aka the final ``.mca`` file. Parameters ---------- file Either a path or a file object, if given region will be saved there. """ # Store all the chunks data as zlib compressed nbt data chunks_data = [] for chunk in self.chunks: if chunk is None: chunks_data.append(None) continue chunk_data = BytesIO() if isinstance(chunk, Chunk): nbt_data = nbt.NBTFile() nbt_data.tags.append( nbt.TAG_Int(name='DataVersion', value=chunk.version)) nbt_data.tags.append(chunk.data) else: nbt_data = chunk.save() nbt_data.write_file(buffer=chunk_data) chunk_data.seek(0) chunk_data = zlib.compress(chunk_data.read()) chunks_data.append(chunk_data) # This is what is added after the location and timestamp header chunks_bytes = bytes() offsets = [] for chunk in chunks_data: if chunk is None: offsets.append(None) continue # 4 bytes are for length, b'\x02' is the compression type which is 2 since its using zlib to_add = (len(chunk) + 1).to_bytes(4, 'big') + b'\x02' + chunk # offset in 4KiB sectors sector_offset = len(chunks_bytes) // 4096 sector_count = math.ceil(len(to_add) / 4096) offsets.append((sector_offset, sector_count)) # Padding to be a multiple of 4KiB long to_add += bytes(4096 - (len(to_add) % 4096)) chunks_bytes += to_add locations_header = bytes() for offset in offsets: # None means the chunk is not an actual chunk in the region # and will be 4 null bytes, which represents non-generated chunks to minecraft if offset is None: locations_header += bytes(4) else: # offset is (sector offset, sector count) locations_header += (offset[0] + 2).to_bytes( 3, 'big') + offset[1].to_bytes(1, 'big') # Set them all as 0 timestamps_header = bytes(4096) final = locations_header + timestamps_header + chunks_bytes # Pad file to be a multiple of 4KiB in size # as Minecraft only accepts region files that are like that final += bytes(4096 - (len(final) % 4096)) assert len(final) % 4096 == 0 # just in case # Save to a file if it was given if file: if isinstance(file, str): with open(file, 'wb') as f: f.write(final) else: file.write(final) return final
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)
if template.default_value: 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))