130 lines
4.2 KiB
Python
130 lines
4.2 KiB
Python
#
|
|
# 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) |