# # Import .schematic file # Copyright (c) 2015 Alexander Pruss # # Under MIT License # from mc import * from sys import argv import mcpi.nbt as nbt import json NEED_SUPPORT = set((SAPLING.id,WATER_FLOWING.id,LAVA_FLOWING.id,GRASS_TALL.id,34,FLOWER_YELLOW.id, FLOWER_CYAN.id,MUSHROOM_BROWN.id,MUSHROOM_RED.id,TORCH.id,63,DOOR_WOOD.id,LADDER.id, 66,68,69,70,DOOR_IRON.id,72,75,76,77,SUGAR_CANE.id,93,94,96,104,105,106,108,111, 113,115,116,117,122,127,131,132,141,142,143,145,147,148,149,150,151,154,157, 167,SUNFLOWER.id,176,177,178,183,184,185,186,187,188,189,190,191,192, 193,194,195,196,197)) def getValue(v): if isinstance(v,nbt.TAG_Compound): return getCompound(v) elif isinstance(v,nbt.TAG_List): out = [] for a in v: out.append(getValue(a)) return out else: return v.value def getCompound(nbt): out = {} for key in nbt: out[key] = getValue(nbt[key]) return out def nbtToJson(nbt): return json.dumps(getCompound(nbt)) def importSchematic(mc,path,x0,y0,z0,centerX=False,centerY=False,centerZ=False,clear=False,movePlayer=True): mc.postToChat("Reading "+path); schematic = nbt.NBTFile(path, "rb") sizeX = schematic["Width"].value sizeY = schematic["Height"].value sizeZ = schematic["Length"].value def offset(x,y,z): return x + (y*sizeZ + z)*sizeX px,pz = x0,z0 if centerX: x0 -= sizeX // 2 if centerY: y0 -= sizeY // 2 if centerZ: z0 -= sizeZ // 2 corner1 = (x0,y0,z0) corner2 = (x0+sizeX-1,y0+sizeY-1,z0+sizeZ-1) if clear: mc.setBlocks(corner1,corner2,AIR) blocks = schematic["Blocks"].value data = schematic["Data"].value tileEntities = schematic["TileEntities"] tileEntityDict = {} if not isPE: for e in tileEntities: origCoords = e['x'].value,e['y'].value,e['z'].value e['x'].value += x0 e['y'].value += y0 e['z'].value += z0 tileEntityDict[origCoords] = nbtToJson(e) check1 = lambda b : b != CARPET.id and b not in NEED_SUPPORT check2 = lambda b : b in NEED_SUPPORT check3 = lambda b : b == CARPET.id mc.postToChat("Rendering"); for check in (check1,check2,check3): for y in range(sizeY): if check == check1 and movePlayer: mc.player.setTilePos(px,y0+y,pz) for x in range(sizeX): for z in range(sizeZ): i = offset(x,y,z) b = blocks[i] if b == AIR.id: continue d = data[i] if not check(b): if check == check1: b = AIR.id d = 0 else: continue if b==33 and (d&7)==7: d = (d&8) if (x,y,z) in tileEntityDict: # if b==33: \print x0+x,y0+y,z0+z,x,y,z,b,d,e mc.setBlockWithNBT(x0+x,y0+y,z0+z,b,d,tileEntityDict[(x,y,z)]) else: # if b==33: print x0+x,y0+y,z0+z,x,y,z,b,d mc.setBlock(x0+x,y0+y,z0+z,b,d) print "done" # TODO: entities return corner1,corner2 if __name__=='__main__': if len(argv) >= 2: path = argv[1] else: import Tkinter from tkFileDialog import askopenfilename master = Tkinter.Tk() master.attributes("-topmost", True) path = askopenfilename(filetypes=['schematic {*.schematic}'],title="Open") master.destroy() if not path: exit() mc = Minecraft() pos = mc.player.getTilePos() (corner0,corner1)=importSchematic(mc,path,pos.x,pos.y,pos.z,centerX=True,centerZ=True) mc.postToChat("Done drawing, putting player on top") y = corner1[1] while y > -256 and mc.getBlock(pos.x,y-1,pos.z) == AIR.id: y -= 1 mc.player.setTilePos(pos.x,y,pos.z)