def __init__(self, filename=None, root_tag=None, size=None, mats=alphaMaterials): if not 'blockstateToID' in globals().keys(): from materials import blockstateToID self._author = None self._blocks = None self._palette = None self._entities = [] self._tile_entities = None self._size = None self._version = None self._mat = mats if filename: root_tag = nbt.load(filename) if root_tag: self._root_tag = root_tag self._size = (self._root_tag["size"][0].value, self._root_tag["size"][1].value, self._root_tag["size"][2].value) self._author = self._root_tag.get("author", nbt.TAG_String()).value self._version = self._root_tag.get("version", nbt.TAG_Int(1)).value self._version = self._root_tag.get("DataVersion", nbt.TAG_Int(1)).value self._palette = self.__toPythonPrimitive(self._root_tag["palette"]) self._blocks = zeros(self.Size, dtype=tuple) self._blocks.fill((0, 0)) self._entities = [] self._tile_entities = zeros(self.Size, dtype=nbt.TAG_Compound) self._tile_entities.fill({}) for block in self._root_tag["blocks"]: x, y, z = [p.value for p in block["pos"].value] self._blocks[x, y, z] = blockstateToID( *self.get_state(block["state"].value)) if "nbt" in block: compound = nbt.TAG_Compound() compound.update(block["nbt"]) self._tile_entities[x, y, z] = compound for e in self._root_tag["entities"]: entity = e["nbt"] entity["Pos"] = e["pos"] self._entities.append(entity) elif size: self._root_tag = nbt.TAG_Compound() self._size = size self._blocks = zeros(self.Size, dtype=tuple) self._blocks.fill((0, 0)) self._entities = [] self._tile_entities = zeros(self.Size, dtype=nbt.TAG_Compound) self._tile_entities.fill({})
def __init__(self, cmd="", hover="", block="I", d="u", cond=False, redstone=False, time=0, first=False): name = "minecraft:" + self.nameMap[block] dv = self.dMap[d] if cond: dv += 8 nbtData = nbt.TAG_Compound("", []) nbtData.add(nbt.TAG_Byte("auto", int(not redstone))) nbtData.add(nbt.TAG_String("Command", cmd)) nbtData.add(nbt.TAG_String("CustomName", hover)) nbtData.add(nbt.TAG_Byte("powered", int(block == "R" and not redstone))) if time == 0 and not first: nbtData.add(nbt.TAG_Int("Version", 8)) else: nbtData.add(nbt.TAG_Int("Version", 9)) nbtData.add(nbt.TAG_Byte("ExecuteOnFirstTick", int(first))) nbtData.add(nbt.TAG_Int("TickDelay", time)) nbtData.add(nbt.TAG_Byte("conditionMet", 0)) nbtData.add(nbt.TAG_String("id", "CommandBlock")) nbtData.add(nbt.TAG_Byte("isMovable", 1)) nbtData.add(nbt.TAG_Int("LPCommandMode", 0)) # Not sure what these LPModes do. This works. nbtData.add(nbt.TAG_Byte("LPConditionalMode", 0)) nbtData.add(nbt.TAG_Byte("LPRedstoneMode", 0)) nbtData.add(nbt.TAG_Long("LastExecution", 0)) nbtData.add(nbt.TAG_String("LastOutput", "")) nbtData.add(nbt.TAG_List("LastOutputParams", [])) nbtData.add(nbt.TAG_Int("SuccessCount", 0)) nbtData.add(nbt.TAG_Byte("TrackOutput", 1)) super().__init__(name, dv, nbtData)
def saveToFile(self, filename): schematicDat = nbt.TAG_Compound() schematicDat.name = "Mega Schematic" schematicDat["Width"] = nbt.TAG_Int(self.size[0]) schematicDat["Height"] = nbt.TAG_Int(self.size[1]) schematicDat["Length"] = nbt.TAG_Int(self.size[2]) schematicDat["Materials"] = nbt.TAG_String(self.materials.name) schematicDat.save(self.worldFolder.getFilePath("schematic.dat")) basedir = self.worldFolder.filename assert os.path.isdir(basedir) with closing( zipfile.ZipFile(filename, "w", zipfile.ZIP_STORED, allowZip64=True)) as z: for root, dirs, files in os.walk(basedir): # NOTE: ignore empty directories for fn in files: absfn = os.path.join(root, fn) shutil.move(absfn, absfn.replace("##MCEDIT.TEMP##" + os.sep, "")) absfn = absfn.replace("##MCEDIT.TEMP##" + os.sep, "") zfn = absfn[len(basedir) + len(os.sep):] # XXX: relative path z.write(absfn, zfn)
def _createLevelDat(self, random_seed, last_played): """ Creates a new level.dat root_tag, and puts it in self.root_tag. To write it to the disk, self.save() should be called. :param random_seed: long :param last_played: long :return: None """ with nbt.littleEndianNBT(): root_tag = nbt.TAG_Compound() root_tag["SpawnX"] = nbt.TAG_Int(0) root_tag["SpawnY"] = nbt.TAG_Int(2) root_tag["SpawnZ"] = nbt.TAG_Int(0) if last_played is None: last_played = long(time.time() * 100) if random_seed is None: random_seed = long(numpy.random.random() * 0xffffffffffffffffL) - 0x8000000000000000L self.root_tag = root_tag self.LastPlayed = long(last_played) self.RandomSeed = long(random_seed) self.SizeOnDisk = 0 self.Time = 1 self.LevelName = os.path.basename(self.worldFile.path)
def TileEntities(self): chestTag = nbt.TAG_Compound() chestTag["id"] = nbt.TAG_String("Chest") chestTag["Items"] = nbt.TAG_List(self.root_tag["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 TileEntities(self): chestTag = nbt.TAG_Compound() chest_id = "Chest" split_ver = self.gameVersion.split('.') if int(split_ver[0]) >= 1 and int(split[1]) >= 11: chest_id = "minecraft:chest" chestTag["id"] = nbt.TAG_String(chest_id) chestTag["Items"] = nbt.TAG_List(self.root_tag["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 extractZipSchematicFromIter(sourceLevel, box, zipfilename=None, entities=True): # converts classic blocks to alpha # probably should only apply to alpha levels if zipfilename is None: zipfilename = tempfile.mktemp("zipschematic") p = sourceLevel.adjustExtractionParameters(box) if p is None: return sourceBox, destPoint = p destPoint = (0, 0, 0) tempfolder = tempfile.mktemp("schematic") try: tempSchematic = MCInfdevOldLevel(tempfolder, create=True) tempSchematic.materials = sourceLevel.materials for i in tempSchematic.copyBlocksFromIter(sourceLevel, sourceBox, destPoint, entities=entities, create=True): yield i tempSchematic.saveInPlace( ) # lights not needed for this format - crashes minecraft though schematicDat = nbt.TAG_Compound() schematicDat.name = "Mega Schematic" schematicDat["Width"] = nbt.TAG_Int(sourceBox.size[0]) schematicDat["Height"] = nbt.TAG_Int(sourceBox.size[1]) schematicDat["Length"] = nbt.TAG_Int(sourceBox.size[2]) schematicDat["Materials"] = nbt.TAG_String( tempSchematic.materials.name) schematicDat.save(os.path.join(tempfolder, "schematic.dat")) zipdir(tempfolder, zipfilename) import mclevel yield mclevel.fromFile(zipfilename) finally: # We get here if the generator is GCed also if os.path.exists(tempfolder): shutil.rmtree(tempfolder, False)
def _saveTileEntities(self, db): data = nbt.DataWriter() for subchunk in self.subchunks: if subchunk is None: continue for x in range(16): for y in range(16): for z in range(16): block = subchunk.getBlock(x, y, z) if block.nbt is not None: # Add back the correct position. block.nbt.add(nbt.TAG_Int("x", subchunk.x * 16 + x)) block.nbt.add(nbt.TAG_Int("y", subchunk.y * 16 + y)) block.nbt.add(nbt.TAG_Int("z", subchunk.z * 16 + z)) nbt.encode(block.nbt, data) ldb.put(db, self.keyBase + b"1", data.get())
def Create(cls, tileEntityID, pos=(0, 0, 0), **kw): tileEntityTag = nbt.TAG_Compound() # Refresh the MCEDIT_DEFS and MCEDIT_IDS objects from pymclevel import MCEDIT_DEFS, MCEDIT_IDS _id = MCEDIT_DEFS.get(tileEntityID, tileEntityID) tileEntityTag["id"] = nbt.TAG_String(_id) base = cls.baseStructures.get(tileEntityID, None) if base: for (name, tag) in base: tileEntityTag[name] = tag() if tileEntityID == "Control": if name == "CustomName": tileEntityTag[name] = nbt.TAG_String("@") elif name == "SuccessCount": tileEntityTag[name] = nbt.TAG_Int(0) elif tileEntityID == "MobSpawner": entity = kw.get("entity") if name == "EntityId": tileEntityTag[name] = nbt.TAG_String(MCEDIT_DEFS.get("Pig", "Pig")) if name == "SpawnData": spawn_id = nbt.TAG_String(MCEDIT_DEFS.get("Pig", "Pig"), "id") tileEntityTag["SpawnData"] = tag() if entity: for k, v in entity.iteritems(): tileEntityTag["SpawnData"][k] = deepcopy(v) else: tileEntityTag["SpawnData"].add(spawn_id) cls.setpos(tileEntityTag, pos) return tileEntityTag
def savedData(self): """ Returns the data of the chunk to save to the database. :return: str of 83200 bytes of chunk data. """ def packData(dataArray): """ Repacks the terrain data to Mojang's leveldb library's format. """ assert dataArray.shape[2] == self.world.Height data = numpy.array(dataArray).reshape(16, 16, self.world.Height / 2, 2) data[..., 1] <<= 4 data[..., 1] |= data[..., 0] return numpy.array(data[:, :, :, 1]) if self.dirty: # elements of DirtyColumns are bitfields. Each bit corresponds to a # 16-block segment of the column. We set all of the bits because # we only track modifications at the chunk level. self.DirtyColumns[:] = 255 with nbt.littleEndianNBT(): entityData = "" tileEntityData = "" for ent in self.TileEntities: tileEntityData += ent.save(compressed=False) for ent in self.Entities: v = ent["id"].value # ent["id"] = nbt.TAG_Int(entity.PocketEntity.entityList[v]) id = entity.PocketEntity.getNumId(v) # print id if id >= 1000: print id print type(ent) print ent ent['id'] = nbt.TAG_Int(id) entityData += ent.save(compressed=False) # We have to re-invert after saving otherwise the next save will fail. ent["id"] = nbt.TAG_String(v) terrain = ''.join([ self.Blocks.tostring(), packData(self.Data).tostring(), packData(self.SkyLight).tostring(), packData(self.BlockLight).tostring(), self.DirtyColumns.tostring(), self.GrassColors.tostring(), ]) return terrain, tileEntityData, entityData
def setPlayerSpawnPosition(self, pos, player=None): """ Sets the worlds spawn point to pos. If player is given, sets that players spawn point instead. :param pos: tuple int (x, y, z) :param player: nbt.TAG_Compound, root tag of the player :return: None """ if player is None: playerSpawnTag = self.root_tag else: playerSpawnTag = self.getPlayerTag(player) for name, val in zip(("SpawnX", "SpawnY", "SpawnZ"), pos): playerSpawnTag[name] = nbt.TAG_Int(val)
def toSchematic(self): schem = MCSchematic(shape=self.Size, mats=self._mat) for (x, y, z), value in ndenumerate(self._blocks): b_id, b_data = value schem.Blocks[x, z, y] = b_id schem.Data[x, z, y] = b_data for (x, y, z), value in ndenumerate(self._tile_entities): if not value: continue tag = value tag["x"] = nbt.TAG_Int(x) tag["y"] = nbt.TAG_Int(y) tag["z"] = nbt.TAG_Int(z) schem.addTileEntity(tag) entity_list = nbt.TAG_List() for e in self._entities: entity_list.append(e) schem.root_tag["Entities"] = entity_list return schem
def copyWithOffset(cls, tileEntity, copyOffset): eTag = deepcopy(tileEntity) eTag['x'] = nbt.TAG_Int(tileEntity['x'].value + copyOffset[0]) eTag['y'] = nbt.TAG_Int(tileEntity['y'].value + copyOffset[1]) eTag['z'] = nbt.TAG_Int(tileEntity['z'].value + copyOffset[2]) if eTag['id'].value == "Control": command = eTag['Command'].value # Adjust teleport command coordinates. # /tp <playername> <x> <y> <z> if command.startswith('/tp'): words = command.split(' ') if len(words) > 4: x, y, z = words[2:5] # Only adjust non-relative teleport coordinates. # These coordinates can be either ints or floats. If ints, Minecraft adds # 0.5 to the coordinate to center the player in the block. # We need to preserve the int/float status or else the coordinates will shift. # Note that copyOffset is always ints. def num(x): try: return int(x) except ValueError: return float(x) if x[0] != "~": x = str(num(x) + copyOffset[0]) if y[0] != "~": y = str(num(y) + copyOffset[1]) if z[0] != "~": z = str(num(z) + copyOffset[2]) words[2:5] = x, y, z eTag['Command'].value = ' '.join(words) return eTag
def Create(cls, tileEntityID, pos=(0, 0, 0), **kw): tileEntityTag = nbt.TAG_Compound() tileEntityTag["id"] = nbt.TAG_String(tileEntityID) base = cls.baseStructures.get(tileEntityID, None) if base: for (name, tag) in base: tileEntityTag[name] = tag() if tileEntityID == "Control": if name == "CustomName": tileEntityTag[name] = nbt.TAG_String("@") elif name == "SuccessCount": tileEntityTag[name] = nbt.TAG_Int(0) cls.setpos(tileEntityTag, pos) return tileEntityTag
def setPlayerGameType(self, gametype, player="Player"): """ Sets the game type for player :param gametype: int (0=survival, 1=creative, 2=adventure, 3=spectator) :param player: string of the name of the player. "Player" for SSP player, player_<client-id> for SMP player. :return: None """ # This annoyingly works differently between single- and multi-player. if player == "Player": self.GameType = gametype self.setPlayerAbilities(gametype, player) else: playerTag = self.getPlayerTag(player) playerTag['playerGameType'] = nbt.TAG_Int(gametype) self.setPlayerAbilities(gametype, player)
def identify(directory): if not (os.path.exists(os.path.join(directory, 'region')) or os.path.exists(os.path.join(directory, 'playerdata'))): return False if not (os.path.exists(os.path.join(directory, 'DIM1')) or os.path.exists(os.path.join(directory, 'DIM-1'))): return False if not (os.path.exists(os.path.join(directory, 'data')) or os.path.exists(os.path.join(directory, 'level.dat'))): return False root = nbt.load(os.path.join(directory, 'level.dat')) if 'FML' in root: return False if root.get('Data', nbt.TAG_Compound()).get('Version', nbt.TAG_Compound()).get( 'Id', nbt.TAG_Int(-1)).value < 1451: return False return True
def _savePalette(self, layer): blocks = self.blocks[layer].swapaxes(1, 2).reshape(4096) # Y and Z saved in a inverted order blockIDs = np.empty(4096, dtype=np.uint32) palette = [] mapping = {} for i, block in enumerate(blocks): # Generate the palette nbt for the given block short = (block.name, str(block.properties)) if short not in mapping: if isinstance(block.properties, int): # 1.12 palette.append(nbt.TAG_Compound("", [nbt.TAG_String("name", block.name), nbt.TAG_Short("val", block.properties)])) else: # 1.13 palette.append(nbt.TAG_Compound("", [ nbt.TAG_String("name", block.name), nbt.TAG_Compound("states", block.properties), nbt.TAG_Int("version", 17629200) ])) mapping[short] = len(palette) - 1 blockIDs[i] = mapping[short] return palette, blockIDs
def copyWithOffset(cls, tileEntity, copyOffset, staticCommands, moveSpawnerPos, first, cancelCommandBlockOffset=False): # You'll need to use this function twice # The first time with first equals to True # The second time with first equals to False eTag = deepcopy(tileEntity) eTag['x'] = nbt.TAG_Int(tileEntity['x'].value + copyOffset[0]) eTag['y'] = nbt.TAG_Int(tileEntity['y'].value + copyOffset[1]) eTag['z'] = nbt.TAG_Int(tileEntity['z'].value + copyOffset[2]) def num(x): try: return int(x) except ValueError: return float(x) def coordX(x, argument): if first: x = str(num(x)) + '!' + str(num(x) + copyOffset[0]) elif argument and x.find("!") >= 0: x = x[x.index("!") + 1:] x = str(num(x) + copyOffset[0]) elif not argument and x.find("!") >= 0: x = x[:x.index("!")] return x def coordY(y, argument): if first: y = str(num(y)) + '!' + str(num(y) + copyOffset[1]) elif argument and y.find("!") >= 0: y = y[y.index("!") + 1:] y = str(num(y) + copyOffset[1]) elif not argument and y.find("!") >= 0: y = y[:y.index("!")] return y def coordZ(z, argument): if first: z = str(num(z)) + '!' + str(num(z) + copyOffset[2]) elif argument and z.find("!") >= 0: z = z[z.index("!") + 1:] z = str(num(z) + copyOffset[2]) elif not argument and z.find("!") >= 0: z = z[:z.index("!")] return z def coords(x, y, z, argument): if x[0] != "~": x = coordX(x, argument) if y[0] != "~": y = coordY(y, argument) if z[0] != "~": z = coordZ(z, argument) return x, y, z if eTag['id'].value == 'MobSpawner' or MCEDIT_IDS.get(eTag['id'].value) == 'DEF_BLOCKS_MOB_SPAWNER': mobs = [] if 'SpawnData' in eTag: mob = eTag['SpawnData'] if mob: mobs.append(mob) if 'SpawnPotentials' in eTag: potentials = eTag['SpawnPotentials'] for p in potentials: if 'properties' in p: mobs.extend(p["Properties"]) elif 'Entity' in p: mobs.extend(p["Entity"]) for mob in mobs: # Why do we get a unicode object as tag 'mob'? if "Pos" in mob and mob != "Pos": if first: pos = Entity.pos(mob) x, y, z = [str(part) for part in pos] x, y, z = coords(x, y, z, moveSpawnerPos) mob['Temp1'] = nbt.TAG_String(x) mob['Temp2'] = nbt.TAG_String(y) mob['Temp3'] = nbt.TAG_String(z) elif 'Temp1' in mob and 'Temp2' in mob and 'Temp3' in mob: x = mob['Temp1'] y = mob['Temp2'] z = mob['Temp3'] del mob['Temp1'] del mob['Temp2'] del mob['Temp3'] parts = [] for part in (x, y, z): part = str(part) part = part[13:len(part) - 2] parts.append(part) x, y, z = parts pos = [float(p) for p in coords(x, y, z, moveSpawnerPos)] Entity.setpos(mob, pos) if (eTag['id'].value == "Control" or MCEDIT_IDS.get(eTag['id'].value) == 'DEF_BLOCKS_COMMAND_BLOCK') and not cancelCommandBlockOffset: command = eTag['Command'].value oldCommand = command def selectorCoords(selector): old_selector = selector try: char_num = 0 new_selector = "" dont_copy = 0 if len(selector) > 4: if '0' <= selector[3] <= '9': new_selector = selector[:3] end_char_x = selector.find(',', 4, len(selector) - 1) if end_char_x == -1: end_char_x = len(selector) - 1 x = selector[3:end_char_x] x = coordX(x, staticCommands) new_selector += x + ',' end_char_y = selector.find(',', end_char_x + 1, len(selector) - 1) if end_char_y == -1: end_char_y = len(selector) - 1 y = selector[end_char_x + 1:end_char_y] y = coordY(y, staticCommands) new_selector += y + ',' end_char_z = selector.find(',', end_char_y + 1, len(selector) - 1) if end_char_z == -1: end_char_z = len(selector) - 1 z = selector[end_char_y + 1:end_char_z] z = coordZ(z, staticCommands) new_selector += z + ',' + selector[end_char_z + 1:] else: for char in selector: if dont_copy != 0: dont_copy -= 1 else: if (char != 'x' and char != 'y' and char != 'z') or letter: new_selector += char if char == '[' or char == ',': letter = False else: letter = True elif char == 'x' and not letter: new_selector += selector[char_num:char_num + 2] char_x = char_num + 2 end_char_x = selector.find(',', char_num + 3, len(selector) - 1) if end_char_x == -1: end_char_x = len(selector) - 1 x = selector[char_x:end_char_x] dont_copy = len(x) + 1 x = coordX(x, staticCommands) new_selector += x elif char == 'y' and not letter: new_selector += selector[char_num:char_num + 2] char_y = char_num + 2 end_char_y = selector.find(',', char_num + 3, len(selector) - 1) if end_char_y == -1: end_char_y = len(selector) - 1 y = selector[char_y:end_char_y] dont_copy = len(y) + 1 y = coordY(y, staticCommands) new_selector += y elif char == 'z' and not letter: new_selector += selector[char_num:char_num + 2] char_z = char_num + 2 end_char_z = selector.find(',', char_num + 3, len(selector) - 1) if end_char_z == -1: end_char_z = len(selector) - 1 z = selector[char_z:end_char_z] dont_copy = len(z) + 1 z = coordZ(z, staticCommands) new_selector += z char_num += 1 else: new_selector = old_selector except: new_selector = old_selector finally: return new_selector try: execute = False Slash = False if command[0] == "/": command = command[1:] Slash = True # Adjust command coordinates. words = command.split(' ') i = 0 for word in words: if word[0] == '@': words[i] = selectorCoords(word) i += 1 if command.startswith('execute'): stillExecuting = True execute = True saving_command = "" while stillExecuting: if Slash: saving_command += '/' x, y, z = words[2:5] words[2:5] = coords(x, y, z, staticCommands) if words[5] == 'detect': x, y, z = words[6:9] words[6:9] = coords(x, y, z, staticCommands) saving_command += ' '.join(words[:9]) words = words[9:] else: saving_command += ' '.join(words[:5]) words = words[5:] command = ' '.join(words) saving_command += ' ' Slash = False if command[0] == "/": command = command[1:] Slash = True words = command.split(' ') if not command.startswith('execute'): stillExecuting = False if (command.startswith('tp') and len(words) == 5) or command.startswith( 'particle') or command.startswith('replaceitem block') or ( command.startswith('spawnpoint') and len(words) == 5) or command.startswith('stats block') or ( command.startswith('summon') and len(words) >= 5): x, y, z = words[2:5] words[2:5] = coords(x, y, z, staticCommands) elif command.startswith('blockdata') or command.startswith('setblock') or ( command.startswith('setworldspawn') and len(words) == 4): x, y, z = words[1:4] words[1:4] = coords(x, y, z, staticCommands) elif command.startswith('playsound') and len(words) >= 6: x, y, z = words[3:6] words[3:6] = coords(x, y, z, staticCommands) elif command.startswith('clone'): x1, y1, z1, x2, y2, z2, x, y, z = words[1:10] x1, y1, z1 = coords(x1, y1, z1, staticCommands) x2, y2, z2 = coords(x2, y2, z2, staticCommands) x, y, z = coords(x, y, z, staticCommands) words[1:10] = x1, y1, z1, x2, y2, z2, x, y, z elif command.startswith('fill'): x1, y1, z1, x2, y2, z2 = words[1:7] x1, y1, z1 = coords(x1, y1, z1, staticCommands) x2, y2, z2 = coords(x2, y2, z2, staticCommands) words[1:7] = x1, y1, z1, x2, y2, z2 elif command.startswith('spreadplayers'): x, z = words[1:3] if x[0] != "~": x = coordX(x, staticCommands) if z[0] != "~": z = coordZ(z, staticCommands) words[1:3] = x, z elif command.startswith('worldborder center') and len(words) == 4: x, z = words[2:4] if x[0] != "~": x = coordX(x, staticCommands) if z[0] != "~": z = coordZ(z, staticCommands) words[2:4] = x, z if Slash: command = '/' else: command = "" command += ' '.join(words) if execute: command = saving_command + command eTag['Command'].value = command except: eTag['Command'].value = oldCommand return eTag
def setpos(cls, tag, pos): for a, p in zip('xyz', pos): tag[a] = nbt.TAG_Int(p)
def testList(self): tag = nbt.TAG_List() tag.append(nbt.TAG_Int(258)) del tag[0]
def testCreate(self): "Create an indev level." # 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]) # You can also create and name a tag before adding it to the compound. spawn = nbt.TAG_List( (nbt.TAG_Short(100), nbt.TAG_Short(45), nbt.TAG_Short(55))) spawn.name = "Spawn" mapTag = nbt.TAG_Compound() mapTag.add(spawn) mapTag.name = "Map" level.add(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 saveToFile(self, filename=None): if filename is None: filename = self.filename if filename is None: log.warn(u"Attempted to save an unnamed file in place") return # you fool! self.Data <<= 4 self.Data |= (self.BlockLight & 0xf) self.Blocks = swapaxes(self.Blocks, 0, 2) self.Data = swapaxes(self.Data, 0, 2) mapTag = nbt.TAG_Compound() mapTag["Width"] = nbt.TAG_Short(self.Width) mapTag["Height"] = nbt.TAG_Short(self.Height) mapTag["Length"] = nbt.TAG_Short(self.Length) mapTag["Blocks"] = nbt.TAG_Byte_Array(self.Blocks) mapTag["Data"] = nbt.TAG_Byte_Array(self.Data) self.Blocks = swapaxes(self.Blocks, 0, 2) self.Data = swapaxes(self.Data, 0, 2) mapTag[Spawn] = nbt.TAG_List([nbt.TAG_Short(i) for i in self.Spawn]) self.root_tag["Map"] = mapTag self.Entities.append(self.LocalPlayer) # fix up Entities imported from Alpha worlds def numbersToFloats(ent): for attr in "Motion", "Pos": if attr in ent: ent[attr] = nbt.TAG_List([nbt.TAG_Double(t.value) for t in ent[attr]]) for ent in self.Entities: numbersToFloats(ent) # fix up TileEntities imported from Alpha worlds. for ent in self.TileEntities: if "Pos" not in ent and all(c in ent for c in 'xyz'): ent["Pos"] = nbt.TAG_Int(self.encodePos(ent['x'].value, ent['y'].value, ent['z'].value)) # output_file = gzip.open(self.filename, "wb", compresslevel=1) try: os.rename(filename, filename + ".old") except Exception: pass try: self.root_tag.save(filename) except: os.rename(filename + ".old", filename) try: os.remove(filename + ".old") except Exception: pass self.Entities.remove(self.LocalPlayer) self.BlockLight = self.Data & 0xf self.Data >>= 4
def copyWithOffset(cls, tileEntity, copyOffset, staticCommands, moveSpawnerPos, regenerateUUID, first): #You'll need to use this function twice #The first time with first equals to True #The second time with first equals to False eTag = deepcopy(tileEntity) eTag['x'] = nbt.TAG_Int(tileEntity['x'].value + copyOffset[0]) eTag['y'] = nbt.TAG_Int(tileEntity['y'].value + copyOffset[1]) eTag['z'] = nbt.TAG_Int(tileEntity['z'].value + copyOffset[2]) if regenerateUUID: # Courtesy of SethBling eTag["UUIDMost"] = nbt.TAG_Long((random.getrandbits(47) << 16) | (1 << 12) | random.getrandbits(12)) eTag["UUIDLeast"] = nbt.TAG_Long(-( (7 << 60) | random.getrandbits(60))) def num(x): try: return int(x) except ValueError: return float(x) def coordX(x, argument): if first == True: x = str(num(x)) + '!' + str(num(x) + copyOffset[0]) elif argument == True and x.find("!") >= 0: x = x[x.index("!") + 1:] x = str(num(x) + copyOffset[0]) elif argument == False and x.find("!") >= 0: x = x[:x.index("!")] return x def coordY(y, argument): if first == True: y = str(num(y)) + '!' + str(num(y) + copyOffset[1]) elif argument == True and y.find("!") >= 0: y = y[y.index("!") + 1:] y = str(num(y) + copyOffset[1]) elif argument == False and y.find("!") >= 0: y = y[:y.index("!")] return y def coordZ(z, argument): if first == True: z = str(num(z)) + '!' + str(num(z) + copyOffset[2]) elif argument == True and z.find("!") >= 0: z = z[z.index("!") + 1:] z = str(num(z) + copyOffset[2]) elif argument == False and z.find("!") >= 0: z = z[:z.index("!")] return z def coords(x, y, z, argument): if x[0] != "~": x = coordX(x, argument) if y[0] != "~": y = coordY(y, argument) if z[0] != "~": z = coordZ(z, argument) return x, y, z if eTag['id'].value == 'MobSpawner': mobs = [] mob = eTag.get('SpawnData') if mob: mobs.append(mob) potentials = eTag.get('SpawnPotentials') if potentials: mobs.extend(p["Properties"] for p in potentials) for mob in mobs: if "Pos" in mob: if first == True: pos = Entity.pos(mob) x, y, z = [str(part) for part in pos] x, y, z = coords(x, y, z, moveSpawnerPos) mob['Temp1'] = nbt.TAG_String(x) mob['Temp2'] = nbt.TAG_String(y) mob['Temp3'] = nbt.TAG_String(z) elif 'Temp1' in mob and 'Temp2' in mob and 'Temp3' in mob: x = mob['Temp1'] y = mob['Temp2'] z = mob['Temp3'] del mob['Temp1'] del mob['Temp2'] del mob['Temp3'] parts = [] for part in (x, y, z): part = str(part) part = part[13:len(part) - 2] parts.append(part) x, y, z = parts pos = [ float(p) for p in coords(x, y, z, moveSpawnerPos) ] Entity.setpos(mob, pos) if eTag['id'].value == "Control": command = eTag['Command'].value oldCommand = command def selectorCoords(selector): old_selector = selector try: char_num = 0 x = "" y = "" z = "" new_selector = "" dont_copy = 0 if len(selector) > 4: if selector[3] >= '0' and selector[3] <= '9': new_selector = selector[:3] end_char_x = selector.find(',', 4, len(selector) - 1) if end_char_x == -1: end_char_x = len(selector) - 1 x = selector[3:end_char_x] x = coordX(x, staticCommands) new_selector += x + ',' end_char_y = selector.find(',', end_char_x + 1, len(selector) - 1) if end_char_y == -1: end_char_y = len(selector) - 1 y = selector[end_char_x + 1:end_char_y] y = coordY(y, staticCommands) new_selector += y + ',' end_char_z = selector.find(',', end_char_y + 1, len(selector) - 1) if end_char_z == -1: end_char_z = len(selector) - 1 z = selector[end_char_y + 1:end_char_z] z = coordZ(z, staticCommands) new_selector += z + ',' + selector[end_char_z + 1:] else: for char in selector: if dont_copy != 0: dont_copy -= 1 else: if (char != 'x' and char != 'y' and char != 'z') or letter == True: new_selector += char if char == '[' or char == ',': letter = False else: letter = True elif char == 'x' and letter == False: new_selector += selector[ char_num:char_num + 2] char_x = char_num + 2 end_char_x = selector.find( ',', char_num + 3, len(selector) - 1) if end_char_x == -1: end_char_x = len(selector) - 1 x = selector[char_x:end_char_x] dont_copy = len(x) + 1 x = coordX(x, staticCommands) new_selector += x elif char == 'y' and letter == False: new_selector += selector[ char_num:char_num + 2] char_y = char_num + 2 end_char_y = selector.find( ',', char_num + 3, len(selector) - 1) if end_char_y == -1: end_char_y = len(selector) - 1 y = selector[char_y:end_char_y] dont_copy = len(y) + 1 y = coordY(y, staticCommands) new_selector += y elif char == 'z' and letter == False: new_selector += selector[ char_num:char_num + 2] char_z = char_num + 2 end_char_z = selector.find( ',', char_num + 3, len(selector) - 1) if end_char_z == -1: end_char_z = len(selector) - 1 z = selector[char_z:end_char_z] dont_copy = len(z) + 1 z = coordZ(z, staticCommands) new_selector += z char_num += 1 else: new_selector = old_selector except: new_selector = old_selector finally: return new_selector try: execute = False Slash = False if command[0] == "/": command = command.replace("/", "", 1) Slash = True # Adjust command coordinates. words = command.split(' ') i = 0 for word in words: if word[0] == '@': words[i] = selectorCoords(word) i += 1 if command.startswith('execute'): stillExecuting = True execute = True saving_command = "" while stillExecuting == True: if Slash == True: saving_command += '/' x, y, z = words[2:5] words[2:5] = coords(x, y, z, staticCommands) if words[5] == 'detect': x, y, z = words[6:9] words[6:9] = coords(x, y, z, staticCommands) saving_command += ' '.join(words[:9]) words = words[9:] else: saving_command += ' '.join(words[:5]) words = words[5:] command = ' '.join(words) saving_command += ' ' Slash = False if command[0] == "/": command = command.replace("/", "", 1) Slash = True words = command.split(' ') if not command.startswith('execute'): stillExecuting = False if (command.startswith('tp') and len(words) == 5 ) or command.startswith('particle') or command.startswith( 'replaceitem block') or ( command.startswith('spawnpoint') and len(words) == 5) or command.startswith('stats block') or ( command.startswith('summon') and len(words) >= 5): x, y, z = words[2:5] words[2:5] = coords(x, y, z, staticCommands) elif command.startswith('blockdata') or command.startswith( 'setblock') or (command.startswith('setworldspawn') and len(words) == 4): x, y, z = words[1:4] words[1:4] = coords(x, y, z, staticCommands) elif command.startswith('playsound') and len(words) >= 6: x, y, z = words[3:6] words[3:6] = coords(x, y, z, staticCommands) elif command.startswith('clone'): x1, y1, z1, x2, y2, z2, x, y, z = words[1:10] x1, y1, z1 = coords(x1, y1, z1, staticCommands) x2, y2, z2 = coords(x2, y2, z2, staticCommands) x, y, z = coords(x, y, z, staticCommands) words[1:10] = x1, y1, z1, x2, y2, z2, x, y, z elif command.startswith('fill'): x1, y1, z1, x2, y2, z2 = words[1:7] x1, y1, z1 = coords(x1, y1, z1, staticCommands) x2, y2, z2 = coords(x2, y2, z2, staticCommands) words[1:7] = x1, y1, z1, x2, y2, z2 elif command.startswith('spreadplayers'): x, z = words[1:3] if x[0] != "~": x = coordX(x, staticCommands) if z[0] != "~": z = coordZ(z, staticCommands) words[1:3] = x, z elif command.startswith('worldborder center') and len( words) == 4: x, z = words[2:4] if x[0] != "~": x = coordX(x, staticCommands) if z[0] != "~": z = coordZ(z, staticCommands) words[2:4] = x, z if Slash == True: command = '/' else: command = "" command += ' '.join(words) if execute == True: command = saving_command + command eTag['Command'].value = command except: eTag['Command'].value = oldCommand return eTag
def save(self, filename=""): structure_tag = nbt.TAG_Compound() blocks_tag = nbt.TAG_List() palette_tag = nbt.TAG_List() entities_tag = nbt.TAG_List() palette = [] if not self._author: self._author = "MCEdit-Unified v{}".format(RELEASE_TAG) structure_tag["author"] = nbt.TAG_String(self._author) if self._version: structure_tag["DataVersion"] = nbt.TAG_Int(self.Version) else: structure_tag["DataVersion"] = nbt.TAG_Int( self.SUPPORTED_VERSIONS[-1]) structure_tag["size"] = nbt.TAG_List([ nbt.TAG_Int(self.Size[0]), nbt.TAG_Int(self.Size[1]), nbt.TAG_Int(self.Size[2]) ]) blockstate_api = BlockstateAPI.material_map.get( self._mat, BlockstateAPI.material_map[alphaMaterials]) for z in xrange( self._blocks.shape[2] ): # For some reason, ndenumerate() didn't work, but this does for x in xrange(self._blocks.shape[0]): for y in xrange(self._blocks.shape[1]): value = self._blocks[x, y, z] name, properties = blockstate_api.idToBlockstate(*value) blockstate = blockstate_api.stringifyBlockstate( name, properties) #if blockstate not in index_table: # index_table[blockstate] = len(index_table) #index = index_table[blockstate] if blockstate not in palette: palette.append(blockstate) index = palette.index(blockstate) block = nbt.TAG_Compound() block["state"] = nbt.TAG_Int(index) block["pos"] = nbt.TAG_List( [nbt.TAG_Int(x), nbt.TAG_Int(y), nbt.TAG_Int(z)]) if self._tile_entities[x, y, z]: block["nbt"] = self._tile_entities[x, y, z] blocks_tag.append(block) structure_tag["blocks"] = blocks_tag for blockstate in palette: name, properties = blockstate_api.deStringifyBlockstate(blockstate) state = nbt.TAG_Compound() state["Name"] = nbt.TAG_String(name) if properties: props = nbt.TAG_Compound() for (key, value) in properties.iteritems(): props[key] = nbt.TAG_String(value) state["Properties"] = props palette_tag.insert(palette.index(blockstate), state) structure_tag["palette"] = palette_tag for e in self._entities: entity = nbt.TAG_Compound() pos = e["Pos"] entity["pos"] = pos entity["nbt"] = e blockPos = nbt.TAG_List() for coord in pos: blockPos.append(nbt.TAG_Int(math.floor(coord.value))) entity["blockPos"] = blockPos entities_tag.append(entity) structure_tag["entities"] = entities_tag structure_tag.save(filename)
def __init__(self, filename=''): if type(filename) in (str, unicode): self.delta_x, self.delta_y, self.delta_z = 0, 0, 0 self.size_x, self.size_y, self.size_z = 0, 0, 0 map_block = {} not_found = [] tileentities_list = [ a.lower() for a in TileEntity.baseStructures.keys() ] for k, v in materials.block_map.items(): map_block[v.replace('minecraft:', '')] = k def get_delta(x, y, z, debug=False, f_obj=None): if x < 0 and abs(x) > self.delta_x: self.delta_x = abs(x) if y < 0 and abs(y) > self.delta_y: self.delta_y = abs(y) if z < 0 and abs(z) > self.delta_z: self.delta_z = abs(z) if x + self.delta_x >= self.size_x: self.size_x = x + self.delta_x + 1 if y + self.delta_y >= self.size_y: self.size_y = y + self.delta_y + 1 if z + self.delta_z >= self.size_z: self.size_z = z + self.delta_z + 1 if debug: output_str = '; '.join( ('get_delta: %s, %s %s' % (x, y, z), 'deltas: %s, %s, %s' % (self.delta_x, self.delta_y, self.delta_z), 'size: %s, %s %s' % (self.size_x, self.size_y, self.size_z))) print output_str if f_obj != None: f_obj.write(output_str) raw_data = open(filename).read() lines = re.findall(r'^Block\(.*?\)|^RandomBlock\(.*?\)', raw_data, re.M) # Doubling the schematic size calculation avoids missbuilt objects. # Rework the get_delta function? [ get_delta(*b) for b in [ eval(','.join( a.split('(')[1].split(')')[0].split(',', 3)[:3])) for a in lines ] ] #print 'Size:', self.size_x, self.size_y, self.size_z [ get_delta(*b) for b in [ eval(','.join( a.split('(')[1].split(')')[0].split(',', 3)[:3])) for a in lines ] ] #print 'Size:', self.size_x, self.size_y, self.size_z self.__schem = schematic.MCSchematic(shape=(self.size_x, self.size_y, self.size_z)) def get_block_data(args): x, y, z = args[:3] b = args[3] nbt_data = None if len(args) == 5 and args[4] != None: f_name = os.path.join(os.path.dirname(filename), os.path.normpath(args[4])) if os.path.exists(f_name): nbt_data = nbt.load(f_name) else: print 'Could not find %s' % args[4] print ' Canonical path: %s' % f_name x = int(x) + self.delta_x y = int(y) + self.delta_y z = int(z) + self.delta_z if b != None: b_id, b_state = (b + ':0').split(':')[:2] else: b_id, b_state = '', None if b_state: b_state = int(b_state) else: b_state = 0 return x, y, z, b_id, b_state, nbt_data def get_randomblock_data(args): x, y, z = args[:3] obj = [] bit_id = False bit_path = False bit_chance = False for arg in args[3:]: if not bit_id: obj.append(arg) bit_id = True elif arg.isdigit(): if not bit_path: obj.append(None) bit_path = True obj.append(int(arg)) bit_chance = True else: obj.append(arg) bit_path = True if bit_id and bit_path and bit_chance: chance = randint(1, 100) if chance <= obj[2]: break obj = [] bit_id, bit_path, bit_chance = False, False, False #print 'Selected random object: %s (%s, %s, %s) from %s'%(obj, x, y, z, args[3:]) # Fallback for chances < 100% if not obj: obj = [None, None] return get_block_data((x, y, z, obj[0], obj[1])) def verify_state(id, state): states = corrected_states.get(id, None) if states: if type(states) == tuple: if state not in range(*states): state = states[0] elif type(states) == list: if state not in states: state = states[0] return state for line in lines: if line.startswith('Block') or line.startswith('RandomBlock'): #print 'Parsing', line if line.startswith('Block'): x, y, z, b_id, b_state, nbt_data = get_block_data( line.replace("Block(", "").replace(")", "").strip().split(",")) else: x, y, z, b_id, b_state, nbt_data = get_randomblock_data( line.replace("RandomBlock(", "").replace(")", "").strip().split(",")) b_idn = map_block.get(b_id.lower(), bo3_blocks.get(b_id, None)) if b_idn != None: b_idn = int(b_idn) if b_id.lower() in tileentities_list: if nbt_data == None: nbt_data = nbt.TAG_Compound() nbt_data.add( nbt.TAG_String(name='id', value=b_id.capitalize())) nbt_data.add(nbt.TAG_Int(name='x', value=x)) nbt_data.add(nbt.TAG_Int(name='y', value=y)) nbt_data.add(nbt.TAG_Int(name='z', value=z)) self.__schem.TileEntities.append(nbt_data) try: self.__schem.Blocks[x, z, y] = b_idn self.__schem.Data[x, z, y] = verify_state(b_id, b_state) except Exception, e: print 'Error while building BO3 data:' print e print 'size', self.size_x, self.size_y, self.size_z print line [ get_delta(*b, debug=True) for b in [ eval(','.join( a.split('(')[1].split(')')[0].split( ',', 3)[:3])) for a in lines ] ] elif b_id != '': print 'BO3 Block not found: %s' % b_id
def main(): # parse options and get results parser = argparse.ArgumentParser( description= 'Converts a single building from a Collada file and pastes into a Minecraft world' ) parser.add_argument('--model', required=True, type=str, \ help='relative or absolute path to .kmz file containing Collada model and assets') parser.add_argument('--world', required=True, type=str, \ help='path to main folder of a target Minecraft world') parser.add_argument("-v", "--verbosity", action="count", \ help="increase output verbosity") parser.add_argument("-q", "--quiet", action="store_true", \ help="suppress informational output") args = parser.parse_args() # set up logging log_level = klog_levels.LOG_INFO if args.quiet: log_level = klog_levels.LOG_ERROR if args.verbosity: # v=1 is DEBUG 1, v=2 is DEBUG 2, and so on log_level += args.verbosity log = klogger(log_level) # Name of the model that we'll be processing filename = args.model log.log_info("Converting %s and placing into %s" % \ (os.path.basename(filename), os.path.basename(args.world))) # Determine where to paste into target world zipf = zipfile.ZipFile(args.model, 'r') kmldata = minidom.parse(zipf.open('doc.kml')) zipf = None # Determine location information location = kmldata.getElementsByTagName('Location')[0] latitude = float( location.getElementsByTagName('latitude')[0].childNodes[0].data) longitude = float( location.getElementsByTagName('longitude')[0].childNodes[0].data) altmode = str( kmldata.getElementsByTagName('altitudeMode')[0].childNodes[0].data) altitude = float( location.getElementsByTagName('altitude')[0].childNodes[0].data) # Determine orientation information orientation = kmldata.getElementsByTagName('Orientation')[0] heading = float( orientation.getElementsByTagName('heading')[0].childNodes[0].data) kmldata = None if abs(heading) > 1.0: log.log_fatal("Model specifies heading of %f, but this script does" \ " not support model rotation" % heading) # Get information about the target world yamlfile = open(os.path.join(args.world, 'Region.yaml'), 'r') yamlfile.readline() # discard first line myRegion = yaml.safe_load(yamlfile) yamlfile.close() # Check important things if myRegion["scale"] != 1 or myRegion["vscale"] != 1: log.log_fatal("Currently only scale=1 and vscale=1 are allowed") # Compute the world utm (x,y) for this model. Oddly enough, we can use these # coordinates directly (for the 1:1 scale case. This script just handles that) llextents = myRegion['wgs84extents']['elevation'] easting, northing, utmzone, utmletter = utmll.from_latlon( latitude, longitude) northing = (myRegion['tiles']['ymin'] + myRegion['tiles']['ymax']) * myRegion['tilesize'] \ - northing log.log_debug(1, "Base easting = %d, northing = %d in UTM Zone %d%s" % \ (easting, northing, utmzone, utmletter)) modelBaseLoc = [easting, northing, 0] log.log_debug(1,"Loc: %.10f,%.10f => %d,%d within %s" % \ (latitude, longitude, modelBaseLoc[0], modelBaseLoc[1], str(llextents))) # Open the model and determine its extents model = collada.Collada( filename, ignore=[collada.DaeUnsupportedError, collada.DaeBrokenRefError]) maxs = array([-1e99, -1e99, -1e99]) mins = array([1e99, 1e99, 1e99]) mr = ModelRecurse(log) mins, maxs = mr.recurse_model(model, "extents", [mins, maxs]) log.log_info("Computed model extents: [%f, %f, %f,] to [%f, %f, %f]" % (mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2])) # some sort of scaling information scale = [.01, .01, .01] if model.assetInfo != None and model.assetInfo.unitmeter != None: log.log_debug(1,"This model contains units, %f %s per meter" % \ (model.assetInfo.unitmeter, model.assetInfo.unitname)) scale = model.assetInfo.unitmeter scale = [scale, scale, scale] t2v = Tri2Voxel(model, log) t2v.scale = array(scale) t2v.geom_prep(mins, maxs) # Use extents and modelBaseLoc to compute the world coordinate that # corresponds to the output array's [0,0,0] #cornerBase = t2v.tvoffset[0] * t2v.tvscale[0] cornerBase = np.multiply(t2v.scale, array([-mins[0], maxs[1], 0])) modelBaseLoc -= cornerBase modelBaseLoc = [round(x) for x in modelBaseLoc] log.log_debug(2,"cornerBase is %s, yielding modelBaseLoc of %s" % \ (str(cornerBase), str(modelBaseLoc))) # Convert mr.recurse_model(model, "convert", t2v) # Do the conversion! # Fix orientation t2v.arr3d_id = np.fliplr(t2v.arr3d_id) # Fix block ID array t2v.arr3d_dt = np.fliplr(t2v.arr3d_dt) # Fix damage val array # Print some stats ar1 = np.count_nonzero(t2v.arr3d_id) ar01 = np.prod(t2v.arrdim) log.log_info("%d/%d voxels filled (%.2f%% fill level)" % (ar1, ar01, 100 * ar1 / ar01)) log.log_info("t2v reports %d voxels changed" % t2v.voxchg) # Compute world-scaled altitude information # This must be done after the level height is adjusted, otherwise one of the # (loaded, cached) chunks will have an incorrect height. if altmode == "absolute": sealevel = myRegion['sealevel'] if 'sealevel' in myRegion else 64 modelAltBase = int(altitude * myRegion['vscale'] + sealevel) elif altmode == "relativeToGround": level = mclevel.fromFile(os.path.join(args.world, "level.dat")) xbase = int(round(modelBaseLoc[0] + cornerBase[0])) zbase = int(round(modelBaseLoc[1] + cornerBase[1])) chunk = level.getChunk(int(xbase / 16.), int(zbase / 16.)) voxcol = chunk.Blocks[xbase % 16, zbase % 16, :] voxtop = [i for i, e in enumerate(voxcol) if e != 0][-1] + 1 modelAltBase = int(voxtop + modelBaseLoc[2]) chunk = None level.close() level = None else: log.log_fatal("Unknown altitude mode in KML file.") log.log_info("Model base altitude is %d meters (voxels)" % modelAltBase) # Compute new world height worldheight = int(modelAltBase + t2v.arrdim[2]) worldheight |= worldheight >> 1 worldheight |= worldheight >> 2 worldheight |= worldheight >> 4 worldheight |= worldheight >> 8 worldheight |= worldheight >> 16 worldheight += 1 # Open MC level for computation level = mclevel.fromFile(os.path.join(args.world, "level.dat")) if worldheight > level.Height: log.log_info("World height increased from %d to %d meters" % \ (level.Height,worldheight)) level.Height = worldheight level.root_tag["Data"]["worldHeight"] = nbt.TAG_Int(worldheight) else: log.log_info("World height unmodified at %d meters" % worldheight) # Figure out what chunks will be modified chunksx = [int(np.floor(modelBaseLoc[0]/16.)), \ int(np.floor((modelBaseLoc[0]+t2v.arrdim[0])/16.))] chunksz = [int(np.floor(modelBaseLoc[1]/16.)), \ int(np.floor((modelBaseLoc[1]+t2v.arrdim[1])/16.))] # Modify the chunks with new building data for x in xrange(chunksx[0], 1 + chunksx[1]): for z in xrange(chunksz[0], 1 + chunksz[1]): # Chunk sub-selection chunk = level.getChunk(x, z) xmin = max(0, modelBaseLoc[0] - 16 * x) xmax = min(16, t2v.arrdim[0] + modelBaseLoc[0] - 16 * x) zmin = max(0, modelBaseLoc[1] - 16 * z) zmax = min(16, t2v.arrdim[1] + modelBaseLoc[1] - 16 * z) # Model sub-selection mxmin = (16 * x) + xmin - modelBaseLoc[0] mzmin = (16 * z) + zmin - modelBaseLoc[1] log.log_debug(2,"Copying region %d,%d,%d to %d,%d,%d" % \ (xmin,modelAltBase,zmin,xmax,(modelAltBase+t2v.arrdim[2]),zmax)) log.log_debug(2,"From model %d,%d,%d to %d,%d,%d" % \ (mxmin,0,mzmin,mxmin+(xmax-xmin),t2v.arrdim[2],mzmin+(zmax-zmin))) if xmax <= 0 or zmax <= 0: log.log_debug(1, "Skipping out-of-bounds copy") continue # Checking to make sure numpy isn't going to pitch a fit shapes = [ t2v.arrdim[2], chunk.Data[xmin, zmin, modelAltBase:(modelAltBase + t2v.arrdim[2])].shape[0] ] if shapes[0] != shapes[1]: log.log_fatal("Cannot store resulting model. Chunk (%d,%d) selected height %d does not match " \ "model matrix height %d" % (x, z, shapes[0], shapes[1])) inp = chunk.Blocks[xmin:xmax,zmin:zmax, \ modelAltBase:(modelAltBase+t2v.arrdim[2])] # Data first because Blocks must retain its 0s ind = chunk.Data[xmin:xmax,zmin:zmax, \ modelAltBase:(modelAltBase+t2v.arrdim[2])] chunk.Data[xmin:xmax,zmin:zmax, \ modelAltBase:(modelAltBase+t2v.arrdim[2])] = \ np.where(inp != 0, ind, \ t2v.arr3d_dt[mxmin:mxmin + (xmax-xmin), mzmin:mzmin + (zmax-zmin), :]) # Blocks second. chunk.Blocks[xmin:xmax,zmin:zmax, \ modelAltBase:(modelAltBase+t2v.arrdim[2])] = \ np.where(inp != 0, inp, \ t2v.arr3d_id[mxmin:mxmin + (xmax-xmin), mzmin:mzmin + (zmax-zmin), :]) # And mark the chunk. chunk.chunkChanged() log.log_info("Relighting level...") level.generateLights() log.log_info("Saving level...") level.saveInPlace()
def copyWithOffset(cls, tileEntity, copyOffset, staticCommands, first): #You'll need to use this function twice #The first time with first equals to True #The second time with first equals to False eTag = deepcopy(tileEntity) eTag['x'] = nbt.TAG_Int(tileEntity['x'].value + copyOffset[0]) eTag['y'] = nbt.TAG_Int(tileEntity['y'].value + copyOffset[1]) eTag['z'] = nbt.TAG_Int(tileEntity['z'].value + copyOffset[2]) if eTag['id'].value == "Control": command = eTag['Command'].value execute = False Slash = False if command[0] == "/": command = command.replace("/", "", 1) Slash = True def num(x): try: return int(x) except ValueError: return float(x) def coordX(x): if first == True: x = str(num(x)) + '!' + str(num(x) + copyOffset[0]) elif staticCommands == True: x = x[x.index("!") + 1:] x = str(num(x) + copyOffset[0]) else: x = x[:x.index("!")] return x def coordY(y): if first == True: y = str(num(y)) + '!' + str(num(y) + copyOffset[1]) elif staticCommands == True: y = y[y.index("!") + 1:] y = str(num(y) + copyOffset[1]) else: y = y[:y.index("!")] return y def coordZ(z): if first == True: z = str(num(z)) + '!' + str(num(z) + copyOffset[2]) elif staticCommands == True: z = z[z.index("!") + 1:] z = str(num(z) + copyOffset[2]) else: z = z[:z.index("!")] return z def coords(x, y, z): if x[0] != "~": x = coordX(x) if y[0] != "~": y = coordY(y) if z[0] != "~": z = coordZ(z) return x, y, z def selectorCoords(selector): char_num = 0 x = "" y = "" z = "" new_selector = "" dont_copy = 0 for char in selector: if dont_copy != 0: dont_copy -= 1 else: if char != 'x' and char != 'y' and char != 'z': new_selector += char if char == '[' or char == ',': letter = False else: letter = True elif char == 'x' and letter == False: new_selector += selector[char_num:char_num + 2] char_x = char_num + 2 end_char_x = selector.find(',', char_num + 3, len(selector) - 1) if end_char_x == -1: end_char_x = len(selector) - 1 x = selector[char_x:end_char_x] dont_copy = len(x) + 1 x = coordX(x) new_selector += x elif char == 'y' and letter == False: new_selector += selector[char_num:char_num + 2] char_y = char_num + 2 end_char_y = selector.find(',', char_num + 3, len(selector) - 1) if end_char_y == -1: end_char_y = len(selector) - 1 y = selector[char_y:end_char_y] dont_copy = len(y) + 1 y = coordY(y) new_selector += y elif char == 'z' and letter == False: new_selector += selector[char_num:char_num + 2] char_z = char_num + 2 end_char_z = selector.find(',', char_num + 3, len(selector) - 1) if end_char_z == -1: end_char_z = len(selector) - 1 z = selector[char_z:end_char_z] dont_copy = len(z) + 1 z = coordZ(z) new_selector += z char_num += 1 return new_selector # Adjust command coordinates. words = command.split(' ') i = 0 for word in words: if word[0] == '@': words[i] = selectorCoords(word) i += 1 if command.startswith('execute'): stillExecuting = True execute = True saving_command = "" while stillExecuting == True: if Slash == True: saving_command += '/' x, y, z = words[2:5] words[2:5] = coords(x, y, z) if words[5] == 'detect': x, y, z = words[6:9] words[6:9] = coords(x, y, z) saving_command += ' '.join(words[:9]) words = words[9:] else: saving_command += ' '.join(words[:5]) words = words[5:] command = ' '.join(words) saving_command += ' ' Slash = False if command[0] == "/": command = command.replace("/", "", 1) Slash = True words = command.split(' ') if not command.startswith('execute'): stillExecuting = False if (command.startswith('tp') and len(words) == 5 ) or command.startswith('particle') or command.startswith( 'replaceitem block') or ( command.startswith('spawnpoint') and len(words) == 5) or command.startswith('stats block') or ( command.startswith('summon') and len(words) >= 5): x, y, z = words[2:5] words[2:5] = coords(x, y, z) elif command.startswith('blockdata') or command.startswith( 'setblock') or (command.startswith('setworldspawn') and len(words) == 4): x, y, z = words[1:4] words[1:4] = coords(x, y, z) elif command.startswith('playsound') and len(words) >= 6: x, y, z = words[3:6] words[3:6] = coords(x, y, z) elif command.startswith('clone'): x1, y1, z1, x2, y2, z2, x, y, z = words[1:10] x1, y1, z1 = coords(x1, y1, z1) x2, y2, z2 = coords(x2, y2, z2) x, y, z = coords(x, y, z) words[1:10] = x1, y1, z1, x2, y2, z2, x, y, z elif command.startswith('fill'): x1, y1, z1, x2, y2, z2 = words[1:7] x1, y1, z1 = coords(x1, y1, z1) x2, y2, z2 = coords(x2, y2, z2) words[1:7] = x1, y1, z1, x2, y2, z2 elif command.startswith('spreadplayers'): x, z = words[1:3] if x[0] != "~": x = coordX(x) if z[0] != "~": z = coordZ(z) words[1:3] = x, z elif command.startswith('worldborder center') and len(words) == 4: x, z = words[2:4] if x[0] != "~": x = coordX(x) if z[0] != "~": z = coordZ(z) words[2:4] = x, z if Slash == True: command = '/' else: command = "" command += ' '.join(words) if execute == True: command = saving_command + command eTag['Command'].value = command return eTag
if __name__ == '__main__': #obj = BlockstateRegionFile('C:\\Users\\gotharbg\\Documents\\MC Worlds\\1.13 World\\region\\r.0.0.mca') #obj2 = BlockstateRegionFile('C:\\Users\\gotharbg\\Downloads\\Podshot 1_13 Snapshot\\region\\r.0.0.mca') # world = BlockstateWorld( 'C:\\Users\\gotharbg\\Documents\\Python Projects\\WorldRewriteProto\\tests\\1.13 World' ) save_test = BlockstateRegionFile( world, 'C:\\Users\\gotharbg\\Documents\\Python Projects\\WorldRewriteProto\\tests\\1.13 World\\r.0.0.mca' ) chunk = save_test.getChunk(0, 0) te = nbt.TAG_Compound() te['id'] = nbt.TAG_String('bed') te['x'] = nbt.TAG_Int(1) te['y'] = nbt.TAG_Int(5) te['z'] = nbt.TAG_Int(1) te['color'] = nbt.TAG_Int(15) chunk.TileEntities.append(te) chunk.save() #chunk = obj.getChunk(0,0) #print(chunk.Blocks[0,3,0]) #print(chunk.TileEntities) #chunk.TileEntities.append({'test': 'value'}) #chunk2 = obj2.getChunk(0,0) #print(chunk.TileEntities) #for i in xrange(16): # print(chunk.Blocks[:,i,1])
def copyWithOffset(cls, tileEntity, copyOffset): eTag = deepcopy(tileEntity) eTag['x'] = nbt.TAG_Int(tileEntity['x'].value + copyOffset[0]) eTag['y'] = nbt.TAG_Int(tileEntity['y'].value + copyOffset[1]) eTag['z'] = nbt.TAG_Int(tileEntity['z'].value + copyOffset[2]) return eTag