def TileEntities(self): chestTag = nbt.TAG_Compound() chestTag["id"] = nbt.TAG_String("Chest") chestTag["Items"] = nbt.TAG_List(self.rootTag["Inventory"]) chestTag["x"] = nbt.TAG_Int(0) chestTag["y"] = nbt.TAG_Int(0) chestTag["z"] = nbt.TAG_Int(0) return nbt.TAG_List([chestTag], name="TileEntities")
def saveToFile(self, filename): """ save to file named filename.""" self.Materials = self.blocktypes.name self.rootTag["Blocks"] = nbt.TAG_Byte_Array( self._Blocks[:self.Height, :self.Length, :self.Width].astype( 'uint8')) self.rootTag["Data"].value = self.rootTag[ "Data"].value[:self.Height, :self.Length, :self.Width] add = self._Blocks >> 8 if add.any(): add = add[:self.Height, :self.Length, :self.Width] # WorldEdit AddBlocks compatibility. # The first 4-bit value is stored in the high bits of the first byte. # Increase odd size by one to align slices. packed_add = zeros(add.size + (add.size & 1), 'uint8') packed_add[:add.size] = add.ravel() # Shift even bytes to the left packed_add[::2] <<= 4 # Merge odd bytes into even bytes packed_add[::2] |= packed_add[1::2] # Save only the even bytes, now that they contain the odd bytes in their lower bits. packed_add = packed_add[0::2] self.rootTag["AddBlocks"] = nbt.TAG_Byte_Array(packed_add) entities = [] for e in self.entitiesByChunk.values(): entities.extend(e) tileEntities = [] for te in self.tileEntitiesByChunk.values(): tileEntities.extend(te) self.rootTag["Entities"] = nbt.TAG_List(entities) self.rootTag["TileEntities"] = nbt.TAG_List(tileEntities) log.info( "Saving schematic %s with %d blocks, %d Entities and %d TileEntities", os.path.basename(filename), self.rootTag["Blocks"].value.size, len(self.rootTag["Entities"]), len(self.rootTag["TileEntities"]), ) with open(filename, 'wb') as chunkfh: self.rootTag.save(chunkfh) del self.rootTag["Blocks"] self.rootTag.pop("AddBlocks", None)
def __get__(self, instance, owner): if instance is None: return self tag = instance.rootTag if self.name not in tag: tag[self.name] = nbt.TAG_List() return NBTListProxy(instance, self.name)
def buildNBTTag(self): """ does not recalculate any data or light """ log.debug(u"Saving chunk: {0}".format(self)) chunkTag = self.rootTag.copy() sections = nbt.TAG_List() for _, section in self._sections.iteritems(): if (not section.Blocks.any() and not section.BlockLight.any() and (section.SkyLight == 15).all()): continue sanitizeBlocks(section, self.adapter.blocktypes) sections.append(section.buildNBTTag()) chunkTag["Level"]["Sections"] = sections if len(self.TileTicks) == 0: del chunkTag["Level"]["TileTicks"] log.debug(u"Saved chunk {0}".format(self)) return chunkTag
def __init__(self, adapter, cx, cz, dimName, rootTag=None, create=False): """ :type adapter: mceditlib.anvil.adapter.AnvilWorldAdapter :type cx: int :type cz: int :type dimName: str :type rootTag: mceditlib.nbt.TAG_Compound :type create: bool :return: :rtype: AnvilChunkData """ self.cx = cx self.cz = cz self.dimName = dimName self.adapter = adapter self.rootTag = rootTag self.dirty = False self._sections = {} if create: self._create() else: self._load(rootTag) levelTag = self.rootTag["Level"] if "Biomes" not in levelTag: levelTag["Biomes"] = nbt.TAG_Byte_Array( numpy.empty((16, 16), 'uint8')) levelTag["Biomes"].value[:] = -1 if "TileTicks" not in levelTag: levelTag["TileTicks"] = nbt.TAG_List()
def __get__(self, instance, owner): if instance is None: return self tag = instance.rootTag if self.name not in tag: tag[self.name] = nbt.TAG_List() return self.listProxyClass(instance, self.name, self.compoundRefClass)
def _create(self): chunkTag = nbt.TAG_Compound() chunkTag.name = "" levelTag = nbt.TAG_Compound() chunkTag["Level"] = levelTag levelTag["HeightMap"] = nbt.TAG_Int_Array(numpy.zeros((16, 16), 'uint32').newbyteorder()) levelTag["TerrainPopulated"] = nbt.TAG_Byte(1) levelTag["xPos"] = nbt.TAG_Int(self.cx) levelTag["zPos"] = nbt.TAG_Int(self.cz) levelTag["LastUpdate"] = nbt.TAG_Long(0) levelTag["Entities"] = nbt.TAG_List() levelTag["TileEntities"] = nbt.TAG_List() self.rootTag = chunkTag self.dirty = True
def __set__(self, instance, value): rootTag = instance.rootTag if self.name not in rootTag: if self.listType is None: raise ValueError( "Tried to initialize list with values without setting listType first!" ) rootTag[self.name] = nbt.TAG_List( [self.listType(i) for i in value]) else: tag = rootTag[self.name] for i, v in enumerate(tag): v.value = value[i] instance.dirty = True
def chestWithItemID(cls, itemID, count=64, damage=0): """ Creates a chest with a stack of 'itemID' in each slot. Optionally specify the count of items in each stack. Pass a negative value for damage to create unnaturally sturdy tools. """ rootTag = nbt.TAG_Compound() invTag = nbt.TAG_List() rootTag["Inventory"] = invTag for slot in range(9, 36): itemTag = nbt.TAG_Compound() itemTag["Slot"] = nbt.TAG_Byte(slot) itemTag["Count"] = nbt.TAG_Byte(count) itemTag["id"] = nbt.TAG_Short(itemID) itemTag["Damage"] = nbt.TAG_Short(damage) invTag.append(itemTag) chest = INVEditChest(rootTag, "") return chest
def testModify(self): level = self.testCreate() # Most of the value types work as expected. Here, we replace the entire tag with a TAG_String level["About"]["Author"] = nbt.TAG_String("YARRR~!") # Because the tag type usually doesn't change, # we can replace the string tag's value instead of replacing the entire tag. level["About"]["Author"].value = "Stew Pickles" # Remove members of a TAG_Compound using del, similar to a python dict. del(level["About"]) # Replace all of the wood blocks with gold using a boolean index array blocks = level["Map"]["Blocks"].value blocks[blocks == 5] = 41 level["Entities"][0] = nbt.TAG_Compound([nbt.TAG_String("Creeper", "id"), nbt.TAG_List([nbt.TAG_Double(d) for d in (1, 1, 1)], "Pos")])
class INVEditChest(FakeChunkedLevelAdapter): Width = 1 Height = 1 Length = 1 Blocks = None Data = array([[[0]]], 'uint8') Entities = nbt.TAG_List() Materials = pc_blocktypes @classmethod def _isTagLevel(cls, rootTag): return "Inventory" in rootTag def __init__(self, filename): self.filename = filename rootTag = nbt.load(filename) self.Blocks = array([[[pc_blocktypes.Chest.ID]]], 'uint8') for item in list(rootTag["Inventory"]): slot = item["Slot"].value if slot < 9 or slot >= 36: rootTag["Inventory"].remove(item) else: item[ "Slot"].value -= 9 # adjust for different chest slot indexes self.rootTag = rootTag @property def TileEntities(self): chestTag = nbt.TAG_Compound() chestTag["id"] = nbt.TAG_String("Chest") chestTag["Items"] = nbt.TAG_List(self.rootTag["Inventory"]) chestTag["x"] = nbt.TAG_Int(0) chestTag["y"] = nbt.TAG_Int(0) chestTag["z"] = nbt.TAG_Int(0) return nbt.TAG_List([chestTag], name="TileEntities")
def __get__(self, instance, owner): tag = instance.rootTag if self.name not in tag: tag[self.name] = nbt.TAG_List() return [self.compoundAttrsClass(subTag) for subTag in tag[self.name] ] # xxxxx insert/delete via list proxy
def created_nbt(): # The root of an NBT file is always a TAG_Compound. level = nbt.TAG_Compound(name="MinecraftLevel") # Subtags of a TAG_Compound are automatically named when you use the [] operator. level["About"] = nbt.TAG_Compound() level["About"]["Author"] = nbt.TAG_String("codewarrior") level["About"]["CreatedOn"] = nbt.TAG_Long(time.time()) level["Environment"] = nbt.TAG_Compound() level["Environment"]["SkyBrightness"] = nbt.TAG_Byte(16) level["Environment"]["SurroundingWaterHeight"] = nbt.TAG_Short(32) level["Environment"]["FogColor"] = nbt.TAG_Int(0xcccccc) entity = nbt.TAG_Compound() entity["id"] = nbt.TAG_String("Creeper") entity["Pos"] = nbt.TAG_List( [nbt.TAG_Float(d) for d in (32.5, 64.0, 33.3)]) level["Entities"] = nbt.TAG_List([entity]) spawn = nbt.TAG_List( (nbt.TAG_Short(100), nbt.TAG_Short(45), nbt.TAG_Short(55))) mapTag = nbt.TAG_Compound() mapTag["Spawn"] = spawn level["Map"] = mapTag mapTag2 = nbt.TAG_Compound([spawn]) mapTag2.name = "Map" # I think it looks more familiar with [] syntax. l, w, h = 128, 128, 128 mapTag["Height"] = nbt.TAG_Short(h) # y dimension mapTag["Length"] = nbt.TAG_Short(l) # z dimension mapTag["Width"] = nbt.TAG_Short(w) # x dimension # Byte arrays are stored as numpy.uint8 arrays. mapTag["Blocks"] = nbt.TAG_Byte_Array() mapTag["Blocks"].value = numpy.zeros( l * w * h, dtype=numpy.uint8) # create lots of air! # The blocks array is indexed (y,z,x) for indev levels, so reshape the blocks mapTag["Blocks"].value.shape = (h, l, w) # Replace the bottom layer of the indev level with wood mapTag["Blocks"].value[0, :, :] = 5 # This is a great way to learn the power of numpy array slicing and indexing. mapTag["Data"] = nbt.TAG_Byte_Array() mapTag["Data"].value = numpy.zeros(l * w * h, dtype=numpy.uint8) # Save a few more tag types for completeness level["ShortArray"] = nbt.TAG_Short_Array( numpy.zeros((16, 16), dtype='uint16')) level["IntArray"] = nbt.TAG_Int_Array(numpy.zeros((16, 16), dtype='uint32')) level["Float"] = nbt.TAG_Float(0.3) return level
def testList(): tag = nbt.TAG_List() tag.append(nbt.TAG_Int(258)) del tag[0]
def exportStructure(filename, dim, selection, author=None, excludedBlocks=None): """ Parameters ---------- filename : unicode dim : mceditlib.worldeditor.WorldEditorDimension selection : mceditlib.selection.SelectionBox Returns ------- """ excludedBlocks = set(excludedBlocks or []) rootTag = nbt.TAG_Compound() rootTag['author'] = nbt.TAG_String(author or "Anonymous") rootTag['version'] = nbt.TAG_Int(1) rootTag['size'] = nbt.TAG_List([nbt.TAG_Int(s) for s in selection.size]) entities = rootTag['entities'] = nbt.TAG_List(list_type=nbt.ID_COMPOUND) blocks = rootTag['blocks'] = nbt.TAG_List(list_type=nbt.ID_COMPOUND) palette = rootTag['palette'] = nbt.TAG_List(list_type=nbt.ID_COMPOUND) ox, oy, oz = selection.origin paletteIDs = {} for x, y, z in selection.positions: block = dim.getBlock(x, y, z) if block in excludedBlocks: continue paletteIdx = paletteIDs.get(block.nameAndState, None) if paletteIdx is None: paletteTag = nbt.TAG_Compound() paletteTag['Name'] = nbt.TAG_String(block.internalName) if len(block.stateDict): paletteTag['Properties'] = nbt.TAG_Compound() for k, v in block.stateDict.iteritems(): paletteTag['Properties'][k] = nbt.TAG_String(v) paletteIdx = paletteIDs[block.nameAndState] = len(palette) palette.append(paletteTag) blockTag = nbt.TAG_Compound() blockTag['state'] = nbt.TAG_Int(paletteIdx) blockTag['pos'] = nbt.TAG_List( [nbt.TAG_Int(a) for a in x - ox, y - oy, z - oz]) tileEntity = dim.getTileEntity((x, y, z)) if tileEntity: tileEntity = tileEntity.copyWithOffset(-selection.origin) blockTag['nbt'] = tileEntity.rootTag blocks.append(blockTag) for entity in dim.getEntities(selection): entity = entity.copyWithOffset(-selection.origin) entityTag = nbt.TAG_Compound() entityTag['pos'] = nbt.TAG_List( [nbt.TAG_Double(a) for a in entity.Position]) entityTag['blockPos'] = nbt.TAG_List( [nbt.TAG_Int(int(floor(a))) for a in entity.Position]) entityTag['nbt'] = entity.rootTag entities.append(entityTag) rootTag.save(filename)
def __init__(self, shape=None, filename=None, blocktypes='Alpha', readonly=False, resume=False): """ Creates an object which stores a section of a Minecraft world as an NBT structure. The order of the coordinates for the block arrays in the file is y,z,x. This is the same order used in Minecraft 1.4's chunk sections. :type shape: tuple :param shape: The shape of the schematic as (x, y, z) :type filename: basestring :param filename: Path to a file to load a saved schematic from. :type blocktypes: basestring or BlockTypeSet :param blocktypes: The name of a builtin blocktypes set (one of "Classic", "Alpha", "Pocket") to indicate allowable blocks. The default is Alpha. An instance of BlockTypeSet may be passed instead. :rtype: SchematicFileAdapter """ self.EntityRef = PCEntityRef self.TileEntityRef = PCTileEntityRef if filename is None and shape is None: raise ValueError("shape or filename required to create %s" % self.__class__.__name__) if filename: self.filename = filename if os.path.exists(filename): rootTag = nbt.load(filename) else: rootTag = None else: self.filename = None rootTag = None if blocktypes in blocktypeClassesByName: self.blocktypes = blocktypeClassesByName[blocktypes]() else: assert (isinstance(blocktypes, BlockTypeSet)) self.blocktypes = blocktypes if rootTag: self.rootTag = rootTag if "Materials" in rootTag: self.blocktypes = blocktypeClassesByName[self.Materials]() else: rootTag["Materials"] = nbt.TAG_String(self.blocktypes.name) w = self.rootTag["Width"].value l = self.rootTag["Length"].value h = self.rootTag["Height"].value assert self.rootTag["Blocks"].value.size == w * l * h self._Blocks = self.rootTag["Blocks"].value.astype( 'uint16').reshape(h, l, w) # _Blocks is y, z, x del self.rootTag["Blocks"] if "AddBlocks" in self.rootTag: # Use WorldEdit's "AddBlocks" array to load and store the 4 high bits of a block ID. # Unlike Minecraft's NibbleArrays, this array stores the first block's bits in the # 4 high bits of the first byte. size = (h * l * w) # If odd, add one to the size to make sure the adjacent slices line up. add = numpy.empty(size + (size & 1), 'uint16') # Fill the even bytes with data add[::2] = self.rootTag["AddBlocks"].value # Copy the low 4 bits to the odd bytes add[1::2] = add[::2] & 0xf # Shift the even bytes down add[::2] >>= 4 # Shift every byte up before merging it with Blocks add <<= 8 self._Blocks |= add[:size].reshape(h, l, w) del self.rootTag["AddBlocks"] self.rootTag["Data"].value = self.rootTag["Data"].value.reshape( h, l, w) if "Biomes" in self.rootTag: self.rootTag["Biomes"].value.shape = (l, w) # If BlockIDs is present, it contains an ID->internalName mapping # from the source level's FML tag. if "BlockIDs" in self.rootTag: self.blocktypes.addBlockIDsFromSchematicTag( self.rootTag["BlockIDs"]) # If itemStackVersion is present, it was exported from MCEdit 2.0. # Its value is either 17 or 18, the values of the version constants. # ItemIDs will also be present. # If itemStackVersion is not present, this schematic was exported from # WorldEdit or MCEdit 1.0. The itemStackVersion cannot be determined # without searching the entities for an itemStack and checking # the type of its `id` tag. If no itemStacks are found, the # version defaults to 1.8 which does not need an ItemIDs tag. if "itemStackVersion" in self.rootTag: itemStackVersion = self.rootTag["itemStackVersion"].value if itemStackVersion not in (VERSION_1_7, VERSION_1_8): raise LevelFormatError("Unknown item stack version %d" % itemStackVersion) if itemStackVersion == VERSION_1_7: itemIDs = self.rootTag.get("ItemIDs") if itemIDs is not None: self.blocktypes.addItemIDsFromSchematicTag(itemIDs) self.blocktypes.itemStackVersion = itemStackVersion else: self.blocktypes.itemStackVersion = self.getItemStackVersionFromEntities( ) else: rootTag = nbt.TAG_Compound(name="Schematic") rootTag["Height"] = nbt.TAG_Short(shape[1]) rootTag["Length"] = nbt.TAG_Short(shape[2]) rootTag["Width"] = nbt.TAG_Short(shape[0]) rootTag["Entities"] = nbt.TAG_List() rootTag["TileEntities"] = nbt.TAG_List() rootTag["Materials"] = nbt.TAG_String(self.blocktypes.name) rootTag["itemStackVersion"] = nbt.TAG_Byte( self.blocktypes.itemStackVersion) self._Blocks = zeros((shape[1], shape[2], shape[0]), 'uint16') rootTag["Data"] = nbt.TAG_Byte_Array( zeros((shape[1], shape[2], shape[0]), uint8)) rootTag["Biomes"] = nbt.TAG_Byte_Array( zeros((shape[2], shape[0]), uint8)) self.rootTag = rootTag self.rootTag["BlockIDs"] = blockIDMapping(blocktypes) itemMapping = itemIDMapping(blocktypes) if itemMapping is not None: self.rootTag[ "ItemIDs"] = itemMapping # Only present for Forge 1.7 # Expand blocks and data to chunk edges h16 = (self.Height + 15) & ~0xf l16 = (self.Length + 15) & ~0xf w16 = (self.Width + 15) & ~0xf blocks = self._Blocks self._Blocks = numpy.zeros((h16, l16, w16), blocks.dtype) self._Blocks[:blocks.shape[0], :blocks.shape[1], :blocks. shape[2]] = blocks data = self.rootTag["Data"].value self.rootTag["Data"].value = numpy.zeros((h16, l16, w16), data.dtype) self.rootTag["Data"].value[:data.shape[0], :data.shape[1], :data. shape[2]] = data self.rootTag["Data"].value &= 0xF # discard high bits self.entitiesByChunk = defaultdict(list) for tag in self.rootTag["Entities"]: ref = self.EntityRef(tag) pos = ref.Position cx, cy, cz = pos.chunkPos() self.entitiesByChunk[cx, cz].append(tag) self.tileEntitiesByChunk = defaultdict(list) for tag in self.rootTag["TileEntities"]: ref = self.TileEntityRef(tag) pos = ref.Position cx, cy, cz = pos.chunkPos() self.tileEntitiesByChunk[cx, cz].append(tag)
def __init__(self, shape=None, filename=None, blocktypes='Alpha', readonly=False, resume=False): """ Creates an object which stores a section of a Minecraft world as an NBT structure. The order of the coordinates for the block arrays in the file is y,z,x. This is the same order used in Minecraft 1.4's chunk sections. :type shape: tuple :param shape: The shape of the schematic as (x, y, z) :type filename: basestring :param filename: Path to a file to load a saved schematic from. :type blocktypes: basestring or BlockTypeSet :param blocktypes: The name of a builtin blocktypes set (one of "Classic", "Alpha", "Pocket") to indicate allowable blocks. The default is Alpha. An instance of BlockTypeSet may be passed instead. :rtype: SchematicFileAdapter """ if filename is None and shape is None: raise ValueError("shape or filename required to create %s" % self.__class__.__name__) if filename: self.filename = filename if os.path.exists(filename): rootTag = nbt.load(filename) else: rootTag = None else: self.filename = None rootTag = None if blocktypes in blocktypes_named: self.blocktypes = blocktypes_named[blocktypes] else: assert (isinstance(blocktypes, BlockTypeSet)) self.blocktypes = blocktypes if rootTag: self.rootTag = rootTag if "Materials" in rootTag: self.blocktypes = blocktypes_named[self.Materials] else: rootTag["Materials"] = nbt.TAG_String(self.blocktypes.name) w = self.rootTag["Width"].value l = self.rootTag["Length"].value h = self.rootTag["Height"].value assert self.rootTag["Blocks"].value.size == w * l * h self._Blocks = self.rootTag["Blocks"].value.astype( 'uint16').reshape(h, l, w) # _Blocks is y, z, x del self.rootTag["Blocks"] if "AddBlocks" in self.rootTag: # Use WorldEdit's "AddBlocks" array to load and store the 4 high bits of a block ID. # Unlike Minecraft's NibbleArrays, this array stores the first block's bits in the # 4 high bits of the first byte. size = (h * l * w) # If odd, add one to the size to make sure the adjacent slices line up. add = numpy.empty(size + (size & 1), 'uint16') # Fill the even bytes with data add[::2] = self.rootTag["AddBlocks"].value # Copy the low 4 bits to the odd bytes add[1::2] = add[::2] & 0xf # Shift the even bytes down add[::2] >>= 4 # Shift every byte up before merging it with Blocks add <<= 8 self._Blocks |= add[:size].reshape(h, l, w) del self.rootTag["AddBlocks"] self.rootTag["Data"].value = self.rootTag["Data"].value.reshape( h, l, w) if "Biomes" in self.rootTag: self.rootTag["Biomes"].value.shape = (l, w) else: rootTag = nbt.TAG_Compound(name="Schematic") rootTag["Height"] = nbt.TAG_Short(shape[1]) rootTag["Length"] = nbt.TAG_Short(shape[2]) rootTag["Width"] = nbt.TAG_Short(shape[0]) rootTag["Entities"] = nbt.TAG_List() rootTag["TileEntities"] = nbt.TAG_List() rootTag["Materials"] = nbt.TAG_String(self.blocktypes.name) self._Blocks = zeros((shape[1], shape[2], shape[0]), 'uint16') rootTag["Data"] = nbt.TAG_Byte_Array( zeros((shape[1], shape[2], shape[0]), uint8)) rootTag["Biomes"] = nbt.TAG_Byte_Array( zeros((shape[2], shape[0]), uint8)) self.rootTag = rootTag #expand blocks and data to chunk edges h16 = (self.Height + 15) & ~0xf l16 = (self.Length + 15) & ~0xf w16 = (self.Width + 15) & ~0xf blocks = self._Blocks self._Blocks = numpy.zeros((h16, l16, w16), blocks.dtype) self._Blocks[:blocks.shape[0], :blocks.shape[1], :blocks. shape[2]] = blocks data = self.rootTag["Data"].value self.rootTag["Data"].value = numpy.zeros((h16, l16, w16), data.dtype) self.rootTag["Data"].value[:data.shape[0], :data.shape[1], :data. shape[2]] = data self.rootTag["Data"].value &= 0xF # discard high bits self.Entities = [ self.EntityRef(tag) for tag in self.rootTag["Entities"] ] self.TileEntities = [ self.EntityRef(tag) for tag in self.rootTag["TileEntities"] ]
def __get__(self, instance, owner): tag = instance.rootTag if self.name not in tag: tag[self.name] = nbt.TAG_List() return [i.value for i in tag[self.name]] # xxxxx insert/delete via list proxy